Pilot data Parse bio 4 iPSC lines NPCs, 3 batches

Load libraries

library(CelltypeR)
Warning: replacing previous import ‘data.table::last’ by ‘dplyr::last’ when loading ‘CelltypeR’
Warning: replacing previous import ‘data.table::first’ by ‘dplyr::first’ when loading ‘CelltypeR’
Warning: replacing previous import ‘data.table::between’ by ‘dplyr::between’ when loading ‘CelltypeR’
Warning: replacing previous import ‘dplyr::filter’ by ‘flowCore::filter’ when loading ‘CelltypeR’
Warning: replacing previous import ‘ggplot2::margin’ by ‘randomForest::margin’ when loading ‘CelltypeR’
Warning: replacing previous import ‘dplyr::combine’ by ‘randomForest::combine’ when loading ‘CelltypeR’
Warning: replacing previous import ‘flowCore::filter’ by ‘dplyr::filter’ when loading ‘CelltypeR’
Warning: replacing previous import ‘flowViz::contour’ by ‘graphics::contour’ when loading ‘flowStats’

Attaching package: ‘CelltypeR’

The following object is masked from ‘package:ggplot2’:

    annotate
seu
An object of class Seurat 
58395 features across 23769 samples within 1 assay 
Active assay: RNA (58395 features, 2500 variable features)
 2 dimensional reductions calculated: pca, umap

Idents(seu) <- 'sample'
VlnPlot(seu, pt.size = 0.001, features = c("nFeature_RNA"))
VlnPlot(seu, pt.size = 0.001, features = "nCount_RNA")

VlnPlot(seu, pt.size = 0.001, features = "percent.mt")

Add in labels for batch and disease status and line

#library("CelltypeR")
# CelltypeR library is a library I (Rhalena) made for flow cytometry but uses the seurat object and I made a quick add annotations function.

Seurat_Parse12sample <- seu

# here is the function
annotate <- function(seu, annotations, to_label, annotation_name = "CellType"){
  Idents(seu) <- to_label
  names(annotations) <- levels(seu)
  seu <- RenameIdents(seu, annotations)
  seu <- AddMetaData(object=seu, metadata=Idents(seu), col.name = annotation_name)

}

Idents(Seurat_Parse12sample) <- "sample"
sample.levels <- levels(Seurat_Parse12sample)
# should give the order of sample

# test
Seurat_Parse12sample <- annotate(Seurat_Parse12sample, annotations = sample.levels, to_label = "sample",annotation_name = "sample.test")
table(Seurat_Parse12sample$sample.test)

x2965B3 x2965B1  TD07B3 x3448B1 x3448B2  TD22B3  TD07B2 x3448B3 x2965B2 
   1918    2353    1690    2400    2194    2894    2124    1530    1686 
 TD07B1  TD22B2  TD22B1 
   1496    2186    1298 
table(Seurat_Parse12sample$sample)

 TD07B1  TD07B2  TD07B3  TD22B1  TD22B2  TD22B3 x2965B1 x2965B2 x2965B3 
   1496    2124    1690    1298    2186    2894    2353    1686    1918 
x3448B1 x3448B2 x3448B3 
   2400    2194    1530 
# these match

#input vector we got from the seurat object
# Define regular expression to match first part of the string
pattern <- "^[A-Za-z]+"

# Use gsub() to replace the first part of the string with an empty string
sample.levels.new <- gsub(pattern, "", sample.levels)

# Extract B1, B2, B3 from new vector
batch <- gsub(".*B", "B", sample.levels.new)

Seurat_Parse12sample <- annotate(Seurat_Parse12sample, annotations = batch, to_label = "sample",annotation_name = "Batch")

table(Seurat_Parse12sample$Batch)

  B3   B1   B2 
8032 7547 8190 
table(Seurat_Parse12sample$Batch,Seurat_Parse12sample$sample)
    
     TD07B1 TD07B2 TD07B3 TD22B1 TD22B2 TD22B3 x2965B1 x2965B2 x2965B3
  B3      0      0   1690      0      0   2894       0       0    1918
  B1   1496      0      0   1298      0      0    2353       0       0
  B2      0   2124      0      0   2186      0       0    1686       0
    
     x3448B1 x3448B2 x3448B3
  B3       0       0    1530
  B1    2400       0       0
  B2       0    2194       0
# add the cell line name
# sample vector is still the input vector
# Define regular expression to remove B1, B2, and B3
pattern <- "B[1-3]$"

# Use gsub() to remove B1, B2, and B3 from original vector
sample.levels.new <- gsub(pattern, "", sample.levels)

# Extract starting values from new vector
ipscline <- gsub("B[1-3]$", "", sample.levels.new)
ipscline
 [1] "x2965" "x2965" "TD07"  "x3448" "x3448" "TD22"  "TD07"  "x3448" "x2965"
[10] "TD07"  "TD22"  "TD22" 
Seurat_Parse12sample <- annotate(Seurat_Parse12sample, annotations = ipscline, to_label = "sample",annotation_name = "IPSC_Line")

table(Seurat_Parse12sample$IPSC_Line)

x2965  TD07 x3448  TD22 
 5957  5310  6124  6378 
table(Seurat_Parse12sample$IPSC_Line,Seurat_Parse12sample$sample)
       
        TD07B1 TD07B2 TD07B3 TD22B1 TD22B2 TD22B3 x2965B1 x2965B2 x2965B3
  x2965      0      0      0      0      0      0    2353    1686    1918
  TD07    1496   2124   1690      0      0      0       0       0       0
  x3448      0      0      0      0      0      0       0       0       0
  TD22       0      0      0   1298   2186   2894       0       0       0
       
        x3448B1 x3448B2 x3448B3
  x2965       0       0       0
  TD07        0       0       0
  x3448    2400    2194    1530
  TD22        0       0       0
# add disease status
# we need to know the order of the lines

Idents(Seurat_Parse12sample) <- "IPSC_Line"
line.levels <- levels(Seurat_Parse12sample)
line.levels
[1] "x2965" "TD07"  "x3448" "TD22" 
PDstatus <- c("PD","PD","Con","Con")  # if TD07 and 2965 are PD lines and TD22 and 3448 are control lines
Seurat_Parse12sample <- annotate(Seurat_Parse12sample, annotations = PDstatus, to_label = "IPSC_Line",annotation_name = "DiseaseStatus")

table(Seurat_Parse12sample$DiseaseStatus)

   PD   Con 
11267 12502 
 
table(Seurat_Parse12sample$DiseaseStatus,Seurat_Parse12sample$IPSC_Line)
     
      x2965 TD07 x3448 TD22
  PD   5957 5310     0    0
  Con     0    0  6124 6378
table(Seurat_Parse12sample$Batch,Seurat_Parse12sample$IPSC_Line)
    
     x2965 TD07 x3448 TD22
  B3  1918 1690  1530 2894
  B1  2353 1496  2400 1298
  B2  1686 2124  2194 2186

Save info

saveRDS(Seurat_Parse12sample, "Parse12sample4lines3batchJuly7.RDS")

Align the cell lines and batches, we will align across the 12 samples

# make a list of seurat objects by our cell type variable
sublist <- SplitObject(seu, split.by = "sample")
# normalize and find variable features
for (i in 1:length(sublist)){
  sublist[[i]] <- NormalizeData(sublist[[i]], verbose = FALSE)
  sublist[[i]] <- FindVariableFeatures(sublist[[i]], selection.method = "vst")
}
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
# Create an empty Seurat object to store the integrated data
# Take the first Seurat object from the list as the starting point
integrated_seurat <- subset(sublist[[1]])


# Iterate over the list of Seurat objects
for (i in 1:length(sublist)) {
  # Rename the 'orig.ident' metadata inside the seurat object to match the object name in the list
  sublist[[i]]$orig.ident <- names(sublist)[i]

}

sample.list <- sublist
for (i in 1:length(sample.list)) {
  # Normalize and scale the data
  sample.list[[i]] <- NormalizeData(sample.list[[i]], verbose = FALSE)
  sample.list[[i]] <- ScaleData(sample.list[[i]], verbose = FALSE)
  # Find variable features
  sample.list[[i]] <- FindVariableFeatures(sample.list[[i]], selection.method = "vst")
  # Get the variable features
  variable_features <- VariableFeatures(sample.list[[i]])
  # Run PCA with the variable features
  sample.list[[i]] <- RunPCA(sample.list[[i]], verbose = FALSE, npcs = 30, features = variable_features)
}
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
int.anchors <- FindIntegrationAnchors(object.list = sample.list, dims = 1:30, reduction = "rpca")
Computing 2000 integration features
Scaling features for provided objects

  |                                                  | 0 % ~calculating  
  |+++++                                             | 8 % ~05s          
  |+++++++++                                         | 17% ~04s          
  |+++++++++++++                                     | 25% ~03s          
  |+++++++++++++++++                                 | 33% ~03s          
  |+++++++++++++++++++++                             | 42% ~02s          
  |+++++++++++++++++++++++++                         | 50% ~02s          
  |++++++++++++++++++++++++++++++                    | 58% ~02s          
  |++++++++++++++++++++++++++++++++++                | 67% ~01s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=04s  
Computing within dataset neighborhoods

  |                                                  | 0 % ~calculating  
  |+++++                                             | 8 % ~07s          
  |+++++++++                                         | 17% ~06s          
  |+++++++++++++                                     | 25% ~05s          
  |+++++++++++++++++                                 | 33% ~04s          
  |+++++++++++++++++++++                             | 42% ~04s          
  |+++++++++++++++++++++++++                         | 50% ~03s          
  |++++++++++++++++++++++++++++++                    | 58% ~03s          
  |++++++++++++++++++++++++++++++++++                | 67% ~02s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~02s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=06s  
Finding all pairwise anchors

  |                                                  | 0 % ~calculating  
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 2868 anchors

  |+                                                 | 2 % ~03m 20s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 545 anchors

  |++                                                | 3 % ~03m 01s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 533 anchors

  |+++                                               | 5 % ~02m 54s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 558 anchors

  |++++                                              | 6 % ~02m 53s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 549 anchors

  |++++                                              | 8 % ~02m 56s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 424 anchors

  |+++++                                             | 9 % ~02m 50s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 467 anchors

  |++++++                                            | 11% ~02m 46s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 427 anchors

  |+++++++                                           | 12% ~02m 45s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 340 anchors

  |+++++++                                           | 14% ~02m 41s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 573 anchors

  |++++++++                                          | 15% ~02m 38s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 915 anchors

  |+++++++++                                         | 17% ~02m 38s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 912 anchors

  |++++++++++                                        | 18% ~02m 37s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 519 anchors

  |++++++++++                                        | 20% ~02m 34s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 766 anchors

  |+++++++++++                                       | 21% ~02m 33s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 738 anchors

  |++++++++++++                                      | 23% ~02m 31s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 531 anchors

  |+++++++++++++                                     | 24% ~02m 27s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 505 anchors

  |+++++++++++++                                     | 26% ~02m 24s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 464 anchors

  |++++++++++++++                                    | 27% ~02m 20s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 518 anchors

  |+++++++++++++++                                   | 29% ~02m 17s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 782 anchors

  |++++++++++++++++                                  | 30% ~02m 14s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 892 anchors

  |++++++++++++++++                                  | 32% ~02m 12s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 549 anchors

  |+++++++++++++++++                                 | 33% ~02m 09s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 493 anchors

  |++++++++++++++++++                                | 35% ~02m 05s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 432 anchors

  |+++++++++++++++++++                               | 36% ~02m 01s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 2894 anchors

  |+++++++++++++++++++                               | 38% ~01m 58s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 569 anchors

  |++++++++++++++++++++                              | 39% ~01m 55s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 713 anchors

  |+++++++++++++++++++++                             | 41% ~01m 52s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 494 anchors

  |++++++++++++++++++++++                            | 42% ~01m 49s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 798 anchors

  |++++++++++++++++++++++                            | 44% ~01m 46s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 724 anchors

  |+++++++++++++++++++++++                           | 45% ~01m 43s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 398 anchors

  |++++++++++++++++++++++++                          | 47% ~01m 39s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 456 anchors

  |+++++++++++++++++++++++++                         | 48% ~01m 37s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 415 anchors

  |+++++++++++++++++++++++++                         | 50% ~01m 34s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 931 anchors

  |++++++++++++++++++++++++++                        | 52% ~01m 31s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 570 anchors

  |+++++++++++++++++++++++++++                       | 53% ~01m 28s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 419 anchors

  |++++++++++++++++++++++++++++                      | 55% ~01m 25s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 553 anchors

  |+++++++++++++++++++++++++++++                     | 56% ~01m 22s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 573 anchors

  |+++++++++++++++++++++++++++++                     | 58% ~01m 19s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 2037 anchors

  |++++++++++++++++++++++++++++++                    | 59% ~01m 16s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 409 anchors

  |+++++++++++++++++++++++++++++++                   | 61% ~01m 13s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 413 anchors

  |++++++++++++++++++++++++++++++++                  | 62% ~01m 10s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 566 anchors

  |++++++++++++++++++++++++++++++++                  | 64% ~01m 07s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 472 anchors

  |+++++++++++++++++++++++++++++++++                 | 65% ~01m 04s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 401 anchors

  |++++++++++++++++++++++++++++++++++                | 67% ~01m 01s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 365 anchors

  |+++++++++++++++++++++++++++++++++++               | 68% ~58s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 847 anchors

  |+++++++++++++++++++++++++++++++++++               | 70% ~56s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 835 anchors

  |++++++++++++++++++++++++++++++++++++              | 71% ~53s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 475 anchors

  |+++++++++++++++++++++++++++++++++++++             | 73% ~50s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 772 anchors

  |++++++++++++++++++++++++++++++++++++++            | 74% ~47s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 740 anchors

  |++++++++++++++++++++++++++++++++++++++            | 76% ~45s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 3274 anchors

  |+++++++++++++++++++++++++++++++++++++++           | 77% ~42s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 796 anchors

  |++++++++++++++++++++++++++++++++++++++++          | 79% ~39s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 717 anchors

  |+++++++++++++++++++++++++++++++++++++++++         | 80% ~37s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 811 anchors

  |+++++++++++++++++++++++++++++++++++++++++         | 82% ~34s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 529 anchors

  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~31s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1402 anchors

  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~28s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1446 anchors

  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~25s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 530 anchors

  |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~22s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 582 anchors

  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~19s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 443 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~17s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1047 anchors

  |+++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~14s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 405 anchors

  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~11s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 483 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~08s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 595 anchors

  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~06s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 570 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++++| 98% ~03s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1021 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=03m 01s
integrated_seurat <- IntegrateData(anchorset = int.anchors,  dims = 1:30)
Merging dataset 8 into 4
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 11 into 6
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 1 into 2
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 10 into 3
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 12 into 2 1
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 9 into 6 11
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 2 1 12 into 6 11 9
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 7 into 5
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 3 10 into 4 8
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 4 8 3 10 into 6 11 9 2 1 12
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Merging dataset 5 7 into 6 11 9 2 1 12 4 8 3 10
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
# 
# must set the k weight to the lowest cell count 
# in the parse sample we have over 1530 cells in the smallest count so we don't have to change the k from the 100 default

Now we need to run the workflow on the integrated object

DefaultAssay(integrated_seurat) <- "integrated"
integrated_seurat <- ScaleData(integrated_seurat, verbose = FALSE)
# only the integrated features will be the pca input

integrated_seurat <- RunPCA(integrated_seurat, npcs = 20, verbose = FALSE)
integrated_seurat <- RunUMAP(integrated_seurat, reduction = "pca", dims = 1:20, n.neighbors = 81)

Have a look at the new UMAP

DimPlot(integrated_seurat, group.by = 'sample')

DimPlot(integrated_seurat, group.by = 'Batch')

DimPlot(integrated_seurat, group.by = 'DiseaseStatus')

DimPlot(integrated_seurat, group.by = 'IPSC_Line')

NA
NA
NA
# saveRDS(integrated_seurat, "Integrated12samples.RDS")
# setwd("~/Documents/Data/scRNAseq/ParseExample/Experiment1-mini12")
intergrated_seurat <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/ParseExample/Experiment1-mini12/Integrated12samples.RDS")

Find new clusters

integrated_seurat <- FindClusters(integrated_seurat, resolution = c(0,0.3,0.6,1) )
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 23769
Number of edges: 3304295

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 1.0000
Number of communities: 1
Elapsed time: 16 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 23769
Number of edges: 3304295

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9097
Number of communities: 10
Elapsed time: 20 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 23769
Number of edges: 3304295

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8752
Number of communities: 16
Elapsed time: 23 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 23769
Number of edges: 3304295

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8382
Number of communities: 20
Elapsed time: 20 seconds

integrated_seurat <- intergrated_seurat
DimPlot(integrated_seurat, group.by = "integrated_snn_res.0.3")

DimPlot(integrated_seurat, group.by = "integrated_snn_res.0.6")

DimPlot(integrated_seurat, group.by = "integrated_snn_res.0.3", split.by = "DiseaseStatus")

table(integrated_seurat$DiseaseStatus)

  Con    PD 
12502 11267 

Annotate clusters res 0.3

write(ClusterMarkers, "clusterMarkersres03Integrated.csv")
Error in cat(x, file = file, sep = c(rep.int(sep, ncolumns - 1), "\n"),  : 
  argument 1 (type 'list') cannot be handled by 'cat'
library(enrichR)
Welcome to enrichR
Checking connection ... 
Enrichr ... Connection is Live!
FlyEnrichr ... Connection is available!
WormEnrichr ... Connection is available!
YeastEnrichr ... Connection is available!
FishEnrichr ... Connection is available!
OxEnrichr ... Connection is available!
setEnrichrSite("Enrichr") # Human genes
Connection changed to https://maayanlab.cloud/Enrichr/
Connection is Live!
# list of all the databases
# get the possible libraries
dbs <- listEnrichrDbs()

# this will list the possible libraries
dbs

# select libraries with cell types
db <- c('CellMarker_Augmented_2021','Azimuth_Cell_Types_2021')

# function for a quick look
checkCelltypes <- function(cluster_num = 0){
  clusterX <- ClusterMarkers %>% filter(cluster == cluster_num & avg_log2FC > 0.25)
  genes <- clusterX$gene
  # the cell type libraries
  # get the results for each library
  clusterX.cell <- enrichr(genes, databases = db)
  # visualize the results
print(plotEnrich(clusterX.cell[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'CellMarker_Augmented_2021'))
print(plotEnrich(clusterX.cell[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'Azimuth_Cell_Types_2021'))

}
#heatmap of top markers
top3 <- ClusterMarkers %>% group_by(cluster) %>% top_n(n=3, wt =avg_log2FC)
DoHeatmap(integrated_seurat, features = top3$gene, size = 3, angle = 90, group.by = "integrated_snn_res.0.3")

NA
NA
table(ClusterMarkers$cluster)

  0   1   2   3   4   5   6   7   8   9 
130  38 242 477 134 249 275 417 377 233 

Check each cluster quickly

checkCelltypes(cluster_num = 3)
Uploading data to Enrichr... Done.
  Querying CellMarker_Augmented_2021... Done.
  Querying Azimuth_Cell_Types_2021... Done.
Parsing results... Done.

Look at some expression lists


da_neurons <- c("TH","SLC6A3","SLC18A2","SOX6","NDNF","SNCG","ALDH1A1","CALB1","TACR2","SLC17A6","SLC32A1","OTX2","GRP","LPL","CCK","VIP")
NPC_orStemLike <- c("DCX","NEUROD1","TBR1","PCNA","MKI67","SOX2","NES","PAX6","MASH1")
mature_neurons = c("RBFOX3","SYP","DLG45","VAMP1","VAMP2","TUBB3","SYT1","BSN","HOMER1","SLC17A6")
excitatory_neurons = c("GRIA2","GRIA1","GRIA4","GRIN1","GRIN2B","GRIN2A","GRIN3A","GRIN3","GRIP1","CAMK2A")
inhbitory_neurons = inh = c("GAD1","GAD2", "GAT1","PVALB","GABR2","GABR1","GBRR1","GABRB2","GABRB1","GABRB3","GABRA6","GABRA1","GABRA4","TRAK2")
astrocytes <- c("GFAP","S100B","AQP4","APOE", "SOX9","SLC1A3")
oligodendrocytes <- c("MBP","MOG","OLIG1","OLIG2","SOX10")
opc <- 
radial_glia <- c("PTPRC","AIF1","ADGRE1", "VIM", "TNC","PTPRZ1","FAM107A","HOPX","LIFR",
              "ITGB5","IL6ST","SLC1A3")
epithelial <- c("HES1","HES5","SOX2","SOX10","NES","CDH1","NOTCH1")

microglia <- c("IBA1","P2RY12","P2RY13","TREM119", "GPR34","SIGLECH","TREM2",
               "CX3CR1","FCRLS","OLFML3","HEXB","TGFBR1", "SALL1","MERTK",
               "PROS1")

features_list <- c("MKI67","SOX2","POU5F1","DLX2","PAX6","SOX9","HES1","NES","RBFOX3","MAP2","NCAM1","CD24","GRIA2","GRIN2B","GABBR1","GAD1","GAD2","GABRA1","GABRB2","TH","ALDH1A1","LMX1B","NR4A2","CORIN","CALB1","KCNJ6","CXCR4","ITGA6","SLC1A3","CD44","AQP4","S100B", "PDGFRA","OLIG2","MBP","CLDN11","VIM","VCAM1")

short_list <- c("MKI67","SOX9","HES1","NES","DLX2","RBFOX3","MAP2","TH","CALB1","KCNJ6","SLC1A3","CD44","AQP4","S100B","OLIG2","MBP","VIM")
Idents(integrated_seurat) <- "integrated_snn_res.0.3"

for (i in da_neurons) {
  print(FeaturePlot(integrated_seurat, features = i, min.cutoff = 'q1', max.cutoff = 'q97', label = TRUE))
}
Warning: Could not find TH in the default search locations, found in RNA assay instead
Warning: Could not find SLC6A3 in the default search locations, found in RNA assay instead
Warning: Could not find SLC18A2 in the default search locations, found in RNA assay instead
Warning: Could not find SNCG in the default search locations, found in RNA assay instead
Warning: Could not find ALDH1A1 in the default search locations, found in RNA assay instead
Warning: Could not find TACR2 in the default search locations, found in RNA assay instead
Warning: Could not find SLC32A1 in the default search locations, found in RNA assay instead
Warning: Could not find OTX2 in the default search locations, found in RNA assay instead
Warning: Could not find GRP in the default search locations, found in RNA assay instead
Warning: Could not find CCK in the default search locations, found in RNA assay instead
Warning: Could not find VIP in the default search locations, found in RNA assay instead

Idents(integrated_seurat) <- "integrated_snn_res.0.3"

for (i in NPC_orStemLike) {
  print(FeaturePlot(integrated_seurat, features = i, min.cutoff = 'q1', max.cutoff = 'q97', label = TRUE))
}
Warning: Could not find PCNA in the default search locations, found in RNA assay instead
Warning: Could not find SOX2 in the default search locations, found in RNA assay instead
Warning: Could not find NES in the default search locations, found in RNA assay instead
Warning in FetchData.Seurat(object = object, vars = c(dims, "ident", features),  :
  The following requested variables were not found: MASH1
Error: None of the requested features were found: MASH1 in slot data

Idents(integrated_seurat) <- "integrated_snn_res.0.3"

for (i in astrocytes) {
  print(FeaturePlot(integrated_seurat, features = i, min.cutoff = 'q1', max.cutoff = 'q97', label = TRUE))
}
Warning: Could not find GFAP in the default search locations, found in RNA assay instead
Warning: Could not find S100B in the default search locations, found in RNA assay instead
Warning: Could not find AQP4 in the default search locations, found in RNA assay instead
Warning: Could not find APOE in the default search locations, found in RNA assay instead
Warning: Could not find SOX9 in the default search locations, found in RNA assay instead

Idents(integrated_seurat) <- "integrated_snn_res.0.3"

for (i in radial_glia) {
  print(FeaturePlot(integrated_seurat, features = i, min.cutoff = 'q1', max.cutoff = 'q97', label = TRUE))
}
Warning: Could not find PTPRC in the default search locations, found in RNA assay instead
Warning: Could not find AIF1 in the default search locations, found in RNA assay instead
Warning: Could not find ADGRE1 in the default search locations, found in RNA assay instead
Warning: Could not find VIM in the default search locations, found in RNA assay instead
Warning: Could not find PTPRZ1 in the default search locations, found in RNA assay instead
Warning: Could not find FAM107A in the default search locations, found in RNA assay instead
Warning: Could not find HOPX in the default search locations, found in RNA assay instead
Warning: Could not find ITGB5 in the default search locations, found in RNA assay instead
Warning: Could not find IL6ST in the default search locations, found in RNA assay instead

Idents(integrated_seurat) <- "integrated_snn_res.0.3"

for (i in mature_neurons) {
  print(FeaturePlot(integrated_seurat, features = i, min.cutoff = 'q1', max.cutoff = 'q97', label = TRUE))
}
Warning: Could not find SYP in the default search locations, found in RNA assay instead
Warning in FetchData.Seurat(object = object, vars = c(dims, "ident", features),  :
  The following requested variables were not found: DLG45
Error: None of the requested features were found: DLG45 in slot data


Idents(integrated_seurat) <- "integrated_snn_res.0.3"

for (i in excitatory_neurons) {
  print(FeaturePlot(integrated_seurat, features = i, min.cutoff = 'q1', max.cutoff = 'q97', label = TRUE))
}
Warning: Could not find GRIN1 in the default search locations, found in RNA assay instead
Warning in FetchData.Seurat(object = object, vars = c(dims, "ident", features),  :
  The following requested variables were not found: GRIN3
Error: None of the requested features were found: GRIN3 in slot data

Add annotations - first pass NPC-stem NPC-glia NPC-SOX6 Neurons-Glut Progenitors-div NPC-SOX2-OXT-fibro Neural-Stem stem cell Neuron-GABA Neuron-epithelial


celltypes2 <- c("NPC","NPC","NPC","Neurons","NPC",
                "NPC","NPC","Stem","Neurons","Epithelial")  

integrated_seurat <- annotate(integrated_seurat, annotations = celltypes2, to_label = "integrated_snn_res.0.3",annotation_name = "Celltypes2")

DimPlot(integrated_seurat, label = TRUE)



DimPlot(integrated_seurat, split.by = "DiseaseStatus")

DimPlot(integrated_seurat, split.by = "DiseaseStatus", group.by = "Celltypes1")

NA
NA
celltypes3 <- c("NPC","NPC","NPC","Neurons","NPC-div",
                "Neuro-NPC","Neural-Stem","Stem","Neurons","Neural-epi")  
integrated_seurat <- annotate(integrated_seurat, annotations = celltypes3, to_label = "integrated_snn_res.0.3",annotation_name = "Celltypes3")

DimPlot(integrated_seurat, label = TRUE)

table(integrated_seurat$IPSC_Line)

 TD07  TD22 x2965 x3448 
 5310  6378  5957  6124 

DEG in cell types 3 groups

DGE <- FindMarkers(seu_sub, ident.1 = "PD", ident.2 = "Con")

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~12s          
  |++                                                | 2 % ~13s          
  |++                                                | 3 % ~13s          
  |+++                                               | 4 % ~13s          
  |+++                                               | 5 % ~13s          
  |++++                                              | 6 % ~13s          
  |++++                                              | 7 % ~13s          
  |+++++                                             | 9 % ~12s          
  |+++++                                             | 10% ~12s          
  |++++++                                            | 11% ~12s          
  |++++++                                            | 12% ~12s          
  |+++++++                                           | 13% ~12s          
  |+++++++                                           | 14% ~12s          
  |++++++++                                          | 15% ~12s          
  |++++++++                                          | 16% ~12s          
  |+++++++++                                         | 17% ~12s          
  |++++++++++                                        | 18% ~11s          
  |++++++++++                                        | 19% ~11s          
  |+++++++++++                                       | 20% ~11s          
  |+++++++++++                                       | 21% ~11s          
  |++++++++++++                                      | 22% ~11s          
  |++++++++++++                                      | 23% ~11s          
  |+++++++++++++                                     | 24% ~10s          
  |+++++++++++++                                     | 26% ~10s          
  |++++++++++++++                                    | 27% ~10s          
  |++++++++++++++                                    | 28% ~10s          
  |+++++++++++++++                                   | 29% ~10s          
  |+++++++++++++++                                   | 30% ~10s          
  |++++++++++++++++                                  | 31% ~10s          
  |++++++++++++++++                                  | 32% ~09s          
  |+++++++++++++++++                                 | 33% ~09s          
  |++++++++++++++++++                                | 34% ~09s          
  |++++++++++++++++++                                | 35% ~09s          
  |+++++++++++++++++++                               | 36% ~09s          
  |+++++++++++++++++++                               | 37% ~09s          
  |++++++++++++++++++++                              | 38% ~09s          
  |++++++++++++++++++++                              | 39% ~08s          
  |+++++++++++++++++++++                             | 40% ~08s          
  |+++++++++++++++++++++                             | 41% ~08s          
  |++++++++++++++++++++++                            | 43% ~08s          
  |++++++++++++++++++++++                            | 44% ~08s          
  |+++++++++++++++++++++++                           | 45% ~08s          
  |+++++++++++++++++++++++                           | 46% ~07s          
  |++++++++++++++++++++++++                          | 47% ~07s          
  |++++++++++++++++++++++++                          | 48% ~07s          
  |+++++++++++++++++++++++++                         | 49% ~07s          
  |+++++++++++++++++++++++++                         | 50% ~07s          
  |++++++++++++++++++++++++++                        | 51% ~07s          
  |+++++++++++++++++++++++++++                       | 52% ~07s          
  |+++++++++++++++++++++++++++                       | 53% ~06s          
  |++++++++++++++++++++++++++++                      | 54% ~06s          
  |++++++++++++++++++++++++++++                      | 55% ~06s          
  |+++++++++++++++++++++++++++++                     | 56% ~06s          
  |+++++++++++++++++++++++++++++                     | 57% ~06s          
  |++++++++++++++++++++++++++++++                    | 59% ~06s          
  |++++++++++++++++++++++++++++++                    | 60% ~05s          
  |+++++++++++++++++++++++++++++++                   | 61% ~05s          
  |+++++++++++++++++++++++++++++++                   | 62% ~05s          
  |++++++++++++++++++++++++++++++++                  | 63% ~05s          
  |++++++++++++++++++++++++++++++++                  | 64% ~05s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~05s          
  |+++++++++++++++++++++++++++++++++                 | 66% ~05s          
  |++++++++++++++++++++++++++++++++++                | 67% ~04s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~04s          
  |+++++++++++++++++++++++++++++++++++               | 69% ~04s          
  |++++++++++++++++++++++++++++++++++++              | 70% ~04s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~04s          
  |+++++++++++++++++++++++++++++++++++++             | 72% ~04s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~04s          
  |++++++++++++++++++++++++++++++++++++++            | 74% ~03s          
  |++++++++++++++++++++++++++++++++++++++            | 76% ~03s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~03s          
  |+++++++++++++++++++++++++++++++++++++++           | 78% ~03s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~03s          
  |++++++++++++++++++++++++++++++++++++++++          | 80% ~03s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~03s          
  |+++++++++++++++++++++++++++++++++++++++++         | 82% ~02s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 84% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~02s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~02s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 88% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=13s  
DimPlot(seu_sub, group.by = "DiseaseStatus")

table(seu_sub$DiseaseStatus)

 Con   PD 
1746 1647 

Neurons DGE volcano plot


library(EnhancedVolcano)
EnhancedVolcano(DGE,
    lab = rownames(DGE),
    #xlim = c(-0.25,0.25),
    x = 'avg_log2FC',
    y = 'p_val_adj',
    pCutoff = 0.000001,
    FCcutoff = 1,
    pointSize = 3.0,
    labSize = 6.0)

NA
NA
NA
head(up)
Error in head(up) : object 'up' not found

Create a sum of counts data table

Try to separately variables in the aggregation

colnames(integrated_seurat@meta.data)
 [1] "orig.ident"             "nCount_RNA"            
 [3] "nFeature_RNA"           "sample"                
 [5] "species"                "gene_count"            
 [7] "tscp_count"             "tscp_count_50dup"      
 [9] "read_count"             "bc1_well"              
[11] "bc2_well"               "bc3_well"              
[13] "bc1_wind"               "bc2_wind"              
[15] "bc3_wind"               "percent.mt"            
[17] "RNA_snn_res.0.5"        "RNA_snn_res.0.6"       
[19] "RNA_snn_res.0.8"        "seurat_clusters"       
[21] "sample.test"            "Batch"                 
[23] "IPSC_Line"              "DiseaseStatus"         
[25] "integrated_snn_res.0"   "integrated_snn_res.0.3"
[27] "integrated_snn_res.0.6" "integrated_snn_res.1"  
[29] "Celltypes1"             "Celltypes2"            
[31] "Celltypes3"            
sum_counts <- AggregateExpression(integrated_seurat, assay = "RNA", group.by = c("Batch","IPSC_Line","DiseaseStatus"))
# this seems to group by the group and the active ident together



colnames(integrated_seurat@meta.data)
 [1] "orig.ident"             "nCount_RNA"            
 [3] "nFeature_RNA"           "sample"                
 [5] "species"                "gene_count"            
 [7] "tscp_count"             "tscp_count_50dup"      
 [9] "read_count"             "bc1_well"              
[11] "bc2_well"               "bc3_well"              
[13] "bc1_wind"               "bc2_wind"              
[15] "bc3_wind"               "percent.mt"            
[17] "RNA_snn_res.0.5"        "RNA_snn_res.0.6"       
[19] "RNA_snn_res.0.8"        "seurat_clusters"       
[21] "sample.test"            "Batch"                 
[23] "IPSC_Line"              "DiseaseStatus"         
[25] "integrated_snn_res.0"   "integrated_snn_res.0.3"
[27] "integrated_snn_res.0.6" "integrated_snn_res.1"  
[29] "Celltypes1"             "Celltypes2"            
[31] "Celltypes3"            
dim(sum_counts$RNA)
[1] 58395    12
sum_counts_df <- as.data.frame(sum_counts$RNA)
dim(sum_counts_df)
[1] 58395    12

Try to make the MDS plots and the DESeq2 DGE

library( "DESeq2" )
Warning: package ‘DESeq2’ was built under R version 4.2.2
Loading required package: S4Vectors
Warning: package ‘S4Vectors’ was built under R version 4.2.2
Loading required package: stats4
Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, aperm, append, as.data.frame, basename, cbind,
    colnames, dirname, do.call, duplicated, eval, evalq, Filter,
    Find, get, grep, grepl, intersect, is.unsorted, lapply, Map,
    mapply, match, mget, order, paste, pmax, pmax.int, pmin,
    pmin.int, Position, rank, rbind, Reduce, rownames, sapply,
    setdiff, sort, table, tapply, union, unique, unsplit,
    which.max, which.min


Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:dplyr’:

    first, rename

The following object is masked from ‘package:tidyr’:

    expand

The following objects are masked from ‘package:base’:

    expand.grid, I, unname

Loading required package: IRanges

Attaching package: ‘IRanges’

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

The following object is masked from ‘package:purrr’:

    reduce

Loading required package: GenomicRanges
Warning: package ‘GenomicRanges’ was built under R version 4.2.2
Loading required package: GenomeInfoDb
Warning: package ‘GenomeInfoDb’ was built under R version 4.2.2
Loading required package: SummarizedExperiment
Loading required package: MatrixGenerics
Loading required package: matrixStats

Attaching package: ‘matrixStats’

The following object is masked from ‘package:dplyr’:

    count


Attaching package: ‘MatrixGenerics’

The following objects are masked from ‘package:matrixStats’:

    colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
    colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
    colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
    colMads, colMaxs, colMeans2, colMedians, colMins,
    colOrderStats, colProds, colQuantiles, colRanges, colRanks,
    colSdDiffs, colSds, colSums2, colTabulates, colVarDiffs,
    colVars, colWeightedMads, colWeightedMeans,
    colWeightedMedians, colWeightedSds, colWeightedVars, rowAlls,
    rowAnyNAs, rowAnys, rowAvgsPerColSet, rowCollapse, rowCounts,
    rowCummaxs, rowCummins, rowCumprods, rowCumsums, rowDiffs,
    rowIQRDiffs, rowIQRs, rowLogSumExps, rowMadDiffs, rowMads,
    rowMaxs, rowMeans2, rowMedians, rowMins, rowOrderStats,
    rowProds, rowQuantiles, rowRanges, rowRanks, rowSdDiffs,
    rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
    rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
    rowWeightedSds, rowWeightedVars

Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with
    'browseVignettes()'. To cite Bioconductor, see
    'citation("Biobase")', and for packages
    'citation("pkgname")'.


Attaching package: ‘Biobase’

The following object is masked from ‘package:MatrixGenerics’:

    rowMedians

The following objects are masked from ‘package:matrixStats’:

    anyMissing, rowMedians


Attaching package: ‘SummarizedExperiment’

The following object is masked from ‘package:SeuratObject’:

    Assays

The following object is masked from ‘package:Seurat’:

    Assays
library(ggplot2)

Read back in the aggregated values (grouped by sample for all clusters)

I need to prepare for DEGseq2

t.df <- t(df.all)
t.df[1:3,1:5]
              TSPAN6     TNMD      DPM1    SCYL3  C1orf112
B1_TD07_PD  226.8531 3.510116  539.7336 354.7319  599.9776
B1_TD22_Con 215.2970 1.233656  510.8297 298.1682  422.9308
B1_x2965_PD 398.1948 4.792417 1022.1249 440.1952 1009.8998

Now add the meta data

Prepare objects for DEGseq2

library( "DESeq2" )
Warning: package ‘DESeq2’ was built under R version 4.2.2
Loading required package: S4Vectors
Warning: package ‘S4Vectors’ was built under R version 4.2.2
Loading required package: stats4
Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, aperm, append, as.data.frame, basename, cbind,
    colnames, dirname, do.call, duplicated, eval, evalq, Filter,
    Find, get, grep, grepl, intersect, is.unsorted, lapply, Map,
    mapply, match, mget, order, paste, pmax, pmax.int, pmin,
    pmin.int, Position, rank, rbind, Reduce, rownames, sapply,
    setdiff, sort, table, tapply, union, unique, unsplit, which.max,
    which.min


Attaching package: ‘S4Vectors’

The following object is masked from ‘package:tidyr’:

    expand

The following objects are masked from ‘package:dplyr’:

    first, rename

The following objects are masked from ‘package:base’:

    expand.grid, I, unname

Loading required package: IRanges

Attaching package: ‘IRanges’

The following object is masked from ‘package:purrr’:

    reduce

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

Loading required package: GenomicRanges
Warning: package ‘GenomicRanges’ was built under R version 4.2.2
Loading required package: GenomeInfoDb
Warning: package ‘GenomeInfoDb’ was built under R version 4.2.2
Loading required package: SummarizedExperiment
Loading required package: MatrixGenerics
Loading required package: matrixStats

Attaching package: ‘matrixStats’

The following object is masked from ‘package:dplyr’:

    count


Attaching package: ‘MatrixGenerics’

The following objects are masked from ‘package:matrixStats’:

    colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
    colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
    colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
    colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
    colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
    colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
    colWeightedMeans, colWeightedMedians, colWeightedSds,
    colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
    rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
    rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
    rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
    rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
    rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs,
    rowVars, rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
    rowWeightedSds, rowWeightedVars

Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with
    'browseVignettes()'. To cite Bioconductor, see
    'citation("Biobase")', and for packages 'citation("pkgname")'.


Attaching package: ‘Biobase’

The following object is masked from ‘package:MatrixGenerics’:

    rowMedians

The following objects are masked from ‘package:matrixStats’:

    anyMissing, rowMedians
# the input is a dataframe with only expression values no meta data
# the dataframe gets transposed back so the initial DF all is correct
dft <- df.all # columns are samples and genes are rows

#prepare the dds object 
# we need the transposed data frame no meta data

dfi <- lapply(dft, as.integer)
dfi <- as.data.frame(dfi)
rownames(dfi) <- rownames(dft)

# here we need the meta data
df.meta <- sample
# and we need what variable to compare

dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta, design = ~DiseaseStatus)
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
# I ran this originally with all data
# see the object
dds
class: DESeqDataSet 
dim: 58395 12 
metadata(1): version
assays(1): counts
rownames(58395): TSPAN6 TNMD ... AP000646.1 AP006216.3
rowData names(0):
colnames(12): B1_TD07_PD B1_TD22_Con ... B3_x2965_PD B3_x3448_Con
colData names(4): sample Batch Line DiseaseStatus

Now we run the DESEQ function

dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing

Look at the results

res <- results(dds)
head(results(dds, tidy= TRUE))
NA
summary(res)

out of 36221 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 351, 0.97%
LFC < 0 (down)     : 567, 1.6%
outliers [1]       : 156, 0.43%
low counts [2]     : 12228, 34%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
library(EnhancedVolcano)
  EnhancedVolcano(res,
    lab = rownames(res),
    x = 'log2FoldChange',
    y = 'pvalue',
    title = 'All cell types NPCs',
    pCutoff = 0.001,
    FCcutoff = 2.5,
    pointSize = 5.0,
    labSize = 5, 
    legendLabSize = 15,
    legendIconSize = 2)


plotPCA(vsdata, intgroup="DiseaseStatus")
plotPCA(vsdata, intgroup="Line")

plotPCA(vsdata, intgroup="Batch")

plotPCA(vsdata, intgroup="sample")

DESeq2 analysis from the cell type separate aggregated data

df <- df %>% select(-"X")
colnames(df)
 [1] "NPC_TD07B1"          "NPC_TD07B2"          "NPC_TD07B3"         
 [4] "NPC_TD22B1"          "NPC_TD22B2"          "NPC_TD22B3"         
 [7] "NPC_x2965B1"         "NPC_x2965B2"         "NPC_x2965B3"        
[10] "NPC_x3448B1"         "NPC_x3448B2"         "NPC_x3448B3"        
[13] "Neurons_TD07B1"      "Neurons_TD07B2"      "Neurons_TD07B3"     
[16] "Neurons_TD22B1"      "Neurons_TD22B2"      "Neurons_TD22B3"     
[19] "Neurons_x2965B1"     "Neurons_x2965B2"     "Neurons_x2965B3"    
[22] "Neurons_x3448B1"     "Neurons_x3448B2"     "Neurons_x3448B3"    
[25] "NPC.div_TD07B1"      "NPC.div_TD07B2"      "NPC.div_TD07B3"     
[28] "NPC.div_TD22B1"      "NPC.div_TD22B2"      "NPC.div_TD22B3"     
[31] "NPC.div_x2965B1"     "NPC.div_x2965B2"     "NPC.div_x2965B3"    
[34] "NPC.div_x3448B1"     "NPC.div_x3448B2"     "NPC.div_x3448B3"    
[37] "Neuro.NPC_TD07B1"    "Neuro.NPC_TD07B2"    "Neuro.NPC_TD07B3"   
[40] "Neuro.NPC_TD22B1"    "Neuro.NPC_TD22B2"    "Neuro.NPC_TD22B3"   
[43] "Neuro.NPC_x2965B1"   "Neuro.NPC_x2965B2"   "Neuro.NPC_x2965B3"  
[46] "Neuro.NPC_x3448B1"   "Neuro.NPC_x3448B2"   "Neuro.NPC_x3448B3"  
[49] "Neural.Stem_TD07B1"  "Neural.Stem_TD07B2"  "Neural.Stem_TD07B3" 
[52] "Neural.Stem_TD22B1"  "Neural.Stem_TD22B2"  "Neural.Stem_TD22B3" 
[55] "Neural.Stem_x2965B1" "Neural.Stem_x2965B2" "Neural.Stem_x2965B3"
[58] "Neural.Stem_x3448B1" "Neural.Stem_x3448B2" "Neural.Stem_x3448B3"
[61] "Stem_TD07B1"         "Stem_TD07B2"         "Stem_TD07B3"        
[64] "Stem_TD22B1"         "Stem_TD22B2"         "Stem_TD22B3"        
[67] "Stem_x2965B1"        "Stem_x2965B2"        "Stem_x2965B3"       
[70] "Stem_x3448B2"        "Neural.epi_TD22B3"   "Neural.epi_x3448B1" 
[73] "Neural.epi_x3448B2"  "Neural.epi_x3448B3" 

Make the metadata

Now set up for the DEG

dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta, design = ~DiseaseStatus)
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
# see the object
dds
class: DESeqDataSet 
dim: 58395 74 
metadata(1): version
assays(1): counts
rownames(58395): TSPAN6 TNMD ... AP000646.1 AP006216.3
rowData names(0):
colnames(74): NPC_TD07B1 NPC_TD07B2 ... Neural.epi_x3448B2
  Neural.epi_x3448B3
colData names(5): Sample Celltype Line Batch DiseaseStatus
# run DeqSeq2
dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 373 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
# see results
res <- results(dds)
head(results(dds, tidy= TRUE))
summary(res)

out of 36120 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 727, 2%
LFC < 0 (down)     : 1254, 3.5%
outliers [1]       : 0, 0%
low counts [2]     : 16262, 45%
(mean count < 0)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

PCA plots

vsdata <- varianceStabilizingTransformation(dds)

plotPCA(vsdata, intgroup="DiseaseStatus")

plotPCA(vsdata, intgroup="Line")

plotPCA(vsdata, intgroup="Batch")

plotPCA(vsdata, intgroup="Sample")

plotPCA(vsdata, intgroup = "Celltype")

Subset full dataframe by cell type

# Assuming df.trans is your transposed dataframe and df.meta is your metadata dataframe

# Load necessary library
#library(DESeq2)

# Extract unique cell types from the "Celltype" column in df.meta
Celltypes <- unique(df.meta$Celltype)
print(Celltypes)
[1] "NPC"         "Neurons"     "NPC.div"     "Neuro.NPC"   "Neural.Stem"
[6] "Stem"        "Neural.epi" 
# Create an empty list to store DESeq results for each cell type
list.results <- list()

df.trans <- as.data.frame(t(df))
dim(df.trans)
[1]    74 58395
#df.trans[1:3,1:5]
#dim(df.meta)


# Loop through each cell type and perform DESeq analysis
for (i in Celltypes) {
  # Subset the expression dataframe by the current cell type
  print(i)
  df_sub <- df.trans[grepl(paste0("^",i,"_"), rownames(df.trans)), ]
  print(dim(df_sub))

  df.meta_sub <- df.meta[df.meta$Celltype == i, ]
  print(dim(df.meta_sub))
# Prepare the DESeq object
  dft <- as.data.frame(t(df_sub)) # Transpose the subset dataframe to get genes as rows and samples as columns
  dfi <- lapply(dft, as.integer)
  dfi <- as.data.frame(dfi)
  rownames(dfi) <- rownames(dft)

  
  # Create the DESeqDataSet object using the subset dataframe and metadata
  dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta_sub, design = ~DiseaseStatus)

  # Perform DESeq analysis
  dds <- DESeq(dds)

  # Store the DESeq results in the list with the cell type as the list index
  res <- results(dds)
  list2 <- list()
  list2[["dds"]] <- dds
  list2[["results"]] <- res
  list.results[[i]] <- list2
}
[1] "NPC"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neurons"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "NPC.div"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neuro.NPC"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neural.Stem"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Stem"
[1]    10 58395
[1] 10  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neural.epi"
[1]     4 58395
[1] 4 5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
Error in DESeqDataSet(se, design = design, ignoreRank) : 
  design has a single variable, with all samples having the same value.
  use instead a design of '~ 1'. estimateSizeFactors, rlog and the VST can then be used

A look at the results


res <- results(dds)
head(results(dds, tidy= TRUE))
summary(res)

out of 34278 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 266, 0.78%
LFC < 0 (down)     : 469, 1.4%
outliers [1]       : 166, 0.48%
low counts [2]     : 12780, 37%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
dds <- list.results$NPC$dds

vsdata <- varianceStabilizingTransformation(dds)

plotPCA(vsdata, intgroup="DiseaseStatus")

plotPCA(vsdata, intgroup="Line")

plotPCA(vsdata, intgroup="Batch")

plotPCA(vsdata, intgroup="Sample")

plotPCA(vsdata, intgroup = "Celltype")


library(EnhancedVolcano)
  EnhancedVolcano(res,
    lab = rownames(res),
    x = 'log2FoldChange',
    y = 'pvalue',
    title = 'NPC',
    ylim = c(0,20),
    pCutoff = 0.01,
    FCcutoff = 2.5,
    pointSize = 5.0,
    labSize = 5, 
    legendLabSize = 15,
    legendIconSize = 5)

Get the DGE dataframe

Create a summary dataframe from the DGE


res1 <- as.data.frame(list.results$Neurons$results)

res1$Celltype <- "Neurons"
res1$Gene <- rownames(res1)
res.sig <- (res1 %>% filter(pvalue <= 0.05)) %>% select(c("Gene","Celltype","log2FoldChange","pvalue","padj"))
res.sig 
NA
NA
NA

Some DGE analysis for NPC to compare


library(enrichR)
Welcome to enrichR
Checking connection ... 
Enrichr ... Connection is Live!
FlyEnrichr ... Connection is available!
WormEnrichr ... Connection is available!
YeastEnrichr ... Connection is available!
FishEnrichr ... Connection is available!
OxEnrichr ... Connection is available!
setEnrichrSite("Enrichr") # Human genes
Connection changed to https://maayanlab.cloud/Enrichr/
Connection is Live!
# list of all the databases
# get the possible libraries
dbs <- listEnrichrDbs()

# this will list the possible libraries
dbs

# select libraries with cell types
db <- c('KEGG_2019_Human','GWAS_Catalog_2019',"GO_Biological_Process_2023",
        "GO_Cellular_Component_2023","GO_Molecular_Function_2023")

# function for a quick look - the names for filtering need to match the column names
getGSA <- function(dataframe, up_or_down = "up", LFCthresh = 0.01,
                          pval_thresh = 0.05){
  if(up_or_down == "up"){
      genelist <- dataframe %>% filter(log2FoldChange >= LFCthresh & padj < pval_thresh)
  }else if (up_or_down == "down") {
      genelist <- dataframe %>% filter(log2FoldChange <= LFCthresh & padj < pval_thresh)
  } else {
    genelist <- dataframe %>% filter(padj < pval_thresh)
  }
genes <- genelist$X
  # the cell type libraries
  # get the results for each library
  results <- enrichr(genes, databases = db)
  # visualize the results
  
print(plotEnrich(results[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'KEGG'))
print(plotEnrich(results[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'GWAS'))
print(plotEnrich(results[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'GObio'))
print(plotEnrich(results[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'GOcell'))
print(plotEnrich(results[[5]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value", title = 'GOmol'))
return(results)
}
# use only the significant after p adjusted genes
# add genes column to DGE it is X if saved to csv
padj$X <- rownames(padj)

pseudoDGEup <- getGSA(padj, up_or_down = "up",
                LFCthresh = 0.02,
                pval_thresh = 0.05)
Uploading data to Enrichr... Done.
  Querying KEGG_2019_Human... Done.
  Querying GWAS_Catalog_2019... Done.
  Querying GO_Biological_Process_2023... Done.
  Querying GO_Cellular_Component_2023... Done.
  Querying GO_Molecular_Function_2023... Done.
Parsing results... Done.

pseudoDGEdown <- getGSA(padj, up_or_down = "down",
                LFCthresh = -0.02,
                pval_thresh = 0.05)
Uploading data to Enrichr... Done.
  Querying KEGG_2019_Human... Done.
  Querying GWAS_Catalog_2019... Done.
  Querying GO_Biological_Process_2023... Done.
  Querying GO_Cellular_Component_2023... Done.
  Querying GO_Molecular_Function_2023... Done.
Parsing results... Done.

pseudoDGEdown <- getGSA(padj, up_or_down = "both",
                LFCthresh = 0,
                pval_thresh = 0.05)
Uploading data to Enrichr... Done.
  Querying KEGG_2019_Human... Done.
  Querying GWAS_Catalog_2019... Done.
  Querying GO_Biological_Process_2023... Done.
  Querying GO_Cellular_Component_2023... Done.
  Querying GO_Molecular_Function_2023... Done.
Parsing results... Done.

Compare genes in wilcoxing rank verse pseudo bulk


sc <- scDGE.NPC %>% filter(p_val_adj <= 0.05)
pb <- res1 %>% filter(padj <= 0.05)

contrast.list <- list(A= sc$X, B= pb$Gene)
# plot the VENN


names(contrast.list) <- c("single cells","pseudobulk")
ggvenn(
  contrast.list, 
  fill_color = c("#0073C2FF", "#EFC000FF", "#868686FF", "#CD534CFF"),
  stroke_size = 0.75, set_name_size = 5, show_percentage = FALSE, text_size = 5, fill_alpha = 0.75
  )
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `text = sprintf("%d", n, 100 * n/sum(n))`.
Caused by warning in `sprintf()`:
! one argument not used by format '%d'

Look for the overlapping genes

down.overlap <- intersect(B,D)
down.overlap
 [1] "GJA1"       "RBM47"      "LRP1B"      "HERC2P3"    "AC105402.3"
 [6] "PURPL"      "AC105411.1" "BCL11A"     "GPC3"       "EMX2OS"    
[11] "HOXB3"      "AC104041.1" "GCNT1"      "AL035425.2" "HOXD3"     
[16] "WNT8B"      "AC023794.1" "HOXB9"      "MIR34AHG"   "HOXA3"     
[21] "HOXC6"      "ARL17B"     "FEZF1-AS1"  "COL14A1"    "ZMAT3"     
[26] "MECOM"      "PCSK5"      "IRS4"       "KCNMB2-AS1" "HOXC4"     
[31] "MIR9-3HG"   "HOXB6"      "WNT7B"      "MIR646HG"   "NR3C2"     
[36] "MDM2"       "TTC29"      "LINC02334"  "EGF"        "KIRREL1"   
[41] "APP"        "PCDH7"      "BCL11B"     "PCAT1"      "LINC02253" 
[46] "RFTN1"      "ADAM23"     "CDH4"       "ADCY2"      "TVP23C"    
[51] "MIR181A1HG" "PAM"        "DCDC1"      "ADAMTS19"   "PLD5"      
[56] "CDH20"      "PGAP1"      "PRKCE"      "SLCO3A1"    "OPHN1"     
[61] "ROR2"       "GRID2"     

Check DGE between cell lines

list.results.lines <- list()

df.trans <- as.data.frame(t(df))
dim(df.trans)
[1]    74 58395
#df.trans[1:3,1:5]
#dim(df.meta)


# Loop through each cell type and perform DESeq analysis
for (i in Celltypes) {
  # Subset the expression dataframe by the current cell type
  print(i)
  df_sub <- df.trans[grepl(paste0("^",i,"_"), rownames(df.trans)), ]
  print(dim(df_sub))

  df.meta_sub <- df.meta[df.meta$Celltype == i, ]
  print(dim(df.meta_sub))
# Prepare the DESeq object
  dft <- as.data.frame(t(df_sub)) # Transpose the subset dataframe to get genes as rows and samples as columns
  dfi <- lapply(dft, as.integer)
  dfi <- as.data.frame(dfi)
  rownames(dfi) <- rownames(dft)

  
  # Create the DESeqDataSet object using the subset dataframe and metadata
  dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta_sub, design = ~Line)

  # Perform DESeq analysis
  dds <- DESeq(dds)

  # Store the DESeq results in the list with the cell type as the list index
  res <- results(dds)
  list2 <- list()
  list2[["dds"]] <- dds
  list2[["results"]] <- res
  list.results.lines[[i]] <- list2
}
[1] "NPC"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neurons"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "NPC.div"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neuro.NPC"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neural.Stem"
[1]    12 58395
[1] 12  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Stem"
[1]    10 58395
[1] 10  5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neural.epi"
[1]     4 58395
[1] 4 5
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
summary(list.results.lines$NPC$results)

out of 34278 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1075, 3.1%
LFC < 0 (down)     : 940, 2.7%
outliers [1]       : 95, 0.28%
low counts [2]     : 13439, 39%
(mean count < 3)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
head(list.results.lines$NPC$results)
log2 fold change (MLE): Line x3448B vs TD07B 
Wald test p-value: Line x3448B vs TD07B 
DataFrame with 6 rows and 6 columns
           baseMean log2FoldChange     lfcSE       stat    pvalue      padj
          <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
TSPAN6   252.946742     0.77507623  0.290873  2.6646566 0.0077067 0.0856281
TNMD       8.869491     4.96264208  1.739830  2.8523718        NA        NA
DPM1     382.043787    -0.00542539  0.150453 -0.0360603 0.9712342 0.9949323
SCYL3    221.859838     0.02439490  0.175854  0.1387225 0.8896695 0.9748766
C1orf112 599.106196    -0.10184738  0.272472 -0.3737899 0.7085606 0.9170440
FGR        0.344874    -0.34434998  4.407356 -0.0781307 0.9377241        NA

To see each contrast:

colnames(x2965_vs_x3448_results)
[1] "baseMean"       "log2FoldChange" "lfcSE"          "stat"          
[5] "pvalue"         "padj"          
# Initialize an empty list to store the results
all_results <- list()

# Loop through each contrast and calculate the results
for (i in 1:length(all_contrasts)) {
  for (j in (i+1):length(all_contrasts)) {
    contrast_level1 <- all_contrasts[i]
    contrast_level2 <- all_contrasts[j]
    
    # Check if both levels are present in dds$Line
    if (contrast_level1 %in% dds$Line & contrast_level2 %in% dds$Line) {
      contrast_name <- paste("Line", contrast_level1, "vs", contrast_level2)
      contrast_result <- results(dds, contrast = c("Line", contrast_level1, contrast_level2), name = contrast_name)
      all_results[[contrast_name]] <- contrast_result
    }
  }
}
Error in checkContrast(contrast, resNames) : 
  x3448B and x3448B should be different level names

Look at other contrasts instead of PD vs HC - HC + PD vs HC + PD and the reverse combo

list2 <- list()
# Loop through each cell type and perform DESeq analysis
for (i in Celltypes) {
  # Subset the expression dataframe by the current cell type
  print(i)
  df_sub <- df.trans[grepl(paste0("^",i,"_"), rownames(df.trans)), ]
  print(dim(df_sub))

  df.meta_sub <- df.meta[df.meta$Celltype == i, ]
  print(dim(df.meta_sub))
# Prepare the DESeq object
  dft <- as.data.frame(t(df_sub)) # Transpose the subset dataframe to get genes as rows and samples as columns
  dfi <- lapply(dft, as.integer)
  dfi <- as.data.frame(dfi)
  rownames(dfi) <- rownames(dft)

  
  # Create the DESeqDataSet object using the subset dataframe and metadata
  dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta_sub, design = ~DiseaseStatus)
  # Perform DESeq analysis
  dds <- DESeq(dds)
  # Store the DESeq results in the list with the cell type as the list index
  res <- results(dds)
  list2[["dds.DiseaseStatus"]] <- dds
  list2[["results.DiseaseStatus"]] <- res
  
  # check the other cell type combination mixes
  dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta_sub, design = ~Mix1)
  # Perform DESeq analysis
  dds <- DESeq(dds)
  # Store the DESeq results in the list with the cell type as the list index
  res <- results(dds)
  
  list2[["dds.Mix1"]] <- dds
  list2[["results.Mix1"]] <- res
  
    # check the other cell type combination mixes
  dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta_sub, design = ~Mix2)
  # Perform DESeq analysis
  dds <- DESeq(dds)
  # Store the DESeq results in the list with the cell type as the list index
  res <- results(dds)
  list2[["dds.Mix2"]] <- dds
  list2[["results.Mix2"]] <- res
  
  list.results.lines[[i]] <- list2
}
[1] "NPC"
[1]    12 58395
[1] 12  7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neurons"
[1]    12 58395
[1] 12  7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
[1] "NPC.div"
[1]    12 58395
[1] 12  7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neuro.NPC"
[1]    12 58395
[1] 12  7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neural.Stem"
[1]    12 58395
[1] 12  7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Stem"
[1]    10 58395
[1] 10  7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "Neural.epi"
[1]     4 58395
[1] 4 7
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
Error in DESeqDataSet(se, design = design, ignoreRank) : 
  design has a single variable, with all samples having the same value.
  use instead a design of '~ 1'. estimateSizeFactors, rlog and the VST can then be used

Summarize the results for NPC for the different contrasts

Have a look at the DGE for NPC

summary(res)

out of 34278 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 266, 0.78%
LFC < 0 (down)     : 469, 1.4%
outliers [1]       : 166, 0.48%
low counts [2]     : 12780, 37%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

NPC PD vs Control Volcano

df$X <- rownames(df)
pseudoDGE <- getGSA(df, up_or_down = "both",
                LFCthresh = 0,
                pval_thresh = 0.01)
Uploading data to Enrichr... Done.
  Querying KEGG_2019_Human... Done.
  Querying GWAS_Catalog_2019... Done.
  Querying GO_Biological_Process_2023... Done.
  Querying GO_Cellular_Component_2023... Done.
  Querying GO_Molecular_Function_2023... Done.
Parsing results... Done.

GSEA

Between batches - NPC - not complete


i = "NPC"
df_sub <- df.trans[grepl(paste0("^",i,"_"), rownames(df.trans)), ]
  print(dim(df_sub))

  df.meta_sub <- df.meta[df.meta$Celltype == i, ]
  print(dim(df.meta_sub))
# Prepare the DESeq object
  dft <- as.data.frame(t(df_sub)) # Transpose the subset dataframe to get genes as rows and samples as columns
  dfi <- lapply(dft, as.integer)
  dfi <- as.data.frame(dfi)
  rownames(dfi) <- rownames(dft)

  
  # Create the DESeqDataSet object using the subset dataframe and metadata
  dds <- DESeqDataSetFromMatrix(countData = dfi, colData = df.meta_sub, design = ~Batch)

  res <- results(dds)

Save CSV of each result from a DGE

Rename function - to see

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKUGlsb3QgZGF0YSBQYXJzZSBiaW8gNCBpUFNDIGxpbmVzIE5QQ3MsIDMgYmF0Y2hlcwoKTG9hZCBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShDZWxsdHlwZVIpCgpgYGAKCgpgYGB7cn0KCiMgcmVhZCBpbiB0aGUgZGF0YQojIG91dHB1dCBmcm9tIFBhcnNlIGJpbyBwaXBlbGluZSBhZGFwdGVkIGJ5IFNhZWlkCiMgcnVuIGJ5IFRheWxvcgojIGRhdGEgb2JqZWN0IG1hZGUgYnkgVGF5bG9yCnNldSA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QYXJzZUV4YW1wbGUvRXhwZXJpbWVudDEtbWluaTEyL1NldXJhdF9QYXJzZTEyc2FtcGxlLlJEUyIpCgojIHRoaXMgZGF0YSBvYmplY3QgaGFzIG5vdCBiZWVuIGZpbHRlcmVkCiMgaXQgZG9lcyBoYXZlIFBDQSBhbmQgdmFyaWFibGUgZmVhdHVyZXMKc2V1CgpgYGAKYGBge3J9CgpzZXVbWyJwZXJjZW50Lm10Il1dIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KHNldSwgcGF0dGVybiA9ICJeTVQtIikKSWRlbnRzKHNldSkgPC0gJ29yaWcuaWRlbnQnCnBsb3QgPC0gVmxuUGxvdChzZXUsIHB0LnNpemUgPSAwLjAwMSwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCAibkNvdW50X1JOQSIsICJwZXJjZW50Lm10IiksIG5jb2wgPSAzKQpwbG90CgpJZGVudHMoc2V1KSA8LSAnc2FtcGxlJwpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMDAxLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIpKQpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMDAxLCBmZWF0dXJlcyA9ICJuQ291bnRfUk5BIikKVmxuUGxvdChzZXUsIHB0LnNpemUgPSAwLjAwMSwgZmVhdHVyZXMgPSAicGVyY2VudC5tdCIpCgoKCmBgYAoKQWRkIGluIGxhYmVscyBmb3IgYmF0Y2ggYW5kIGRpc2Vhc2Ugc3RhdHVzIGFuZCBsaW5lCgpgYGB7cn0KI2xpYnJhcnkoIkNlbGx0eXBlUiIpCiMgQ2VsbHR5cGVSIGxpYnJhcnkgaXMgYSBsaWJyYXJ5IEkgKFJoYWxlbmEpIG1hZGUgZm9yIGZsb3cgY3l0b21ldHJ5IGJ1dCB1c2VzIHRoZSBzZXVyYXQgb2JqZWN0IGFuZCBJIG1hZGUgYSBxdWljayBhZGQgYW5ub3RhdGlvbnMgZnVuY3Rpb24uCgpTZXVyYXRfUGFyc2UxMnNhbXBsZSA8LSBzZXUKCiMgaGVyZSBpcyB0aGUgZnVuY3Rpb24KYW5ub3RhdGUgPC0gZnVuY3Rpb24oc2V1LCBhbm5vdGF0aW9ucywgdG9fbGFiZWwsIGFubm90YXRpb25fbmFtZSA9ICJDZWxsVHlwZSIpewogIElkZW50cyhzZXUpIDwtIHRvX2xhYmVsCiAgbmFtZXMoYW5ub3RhdGlvbnMpIDwtIGxldmVscyhzZXUpCiAgc2V1IDwtIFJlbmFtZUlkZW50cyhzZXUsIGFubm90YXRpb25zKQogIHNldSA8LSBBZGRNZXRhRGF0YShvYmplY3Q9c2V1LCBtZXRhZGF0YT1JZGVudHMoc2V1KSwgY29sLm5hbWUgPSBhbm5vdGF0aW9uX25hbWUpCgp9CgpJZGVudHMoU2V1cmF0X1BhcnNlMTJzYW1wbGUpIDwtICJzYW1wbGUiCnNhbXBsZS5sZXZlbHMgPC0gbGV2ZWxzKFNldXJhdF9QYXJzZTEyc2FtcGxlKQojIHNob3VsZCBnaXZlIHRoZSBvcmRlciBvZiBzYW1wbGUKCiMgdGVzdApTZXVyYXRfUGFyc2UxMnNhbXBsZSA8LSBhbm5vdGF0ZShTZXVyYXRfUGFyc2UxMnNhbXBsZSwgYW5ub3RhdGlvbnMgPSBzYW1wbGUubGV2ZWxzLCB0b19sYWJlbCA9ICJzYW1wbGUiLGFubm90YXRpb25fbmFtZSA9ICJzYW1wbGUudGVzdCIpCnRhYmxlKFNldXJhdF9QYXJzZTEyc2FtcGxlJHNhbXBsZS50ZXN0KQp0YWJsZShTZXVyYXRfUGFyc2UxMnNhbXBsZSRzYW1wbGUpCiMgdGhlc2UgbWF0Y2gKCiNpbnB1dCB2ZWN0b3Igd2UgZ290IGZyb20gdGhlIHNldXJhdCBvYmplY3QKIyBEZWZpbmUgcmVndWxhciBleHByZXNzaW9uIHRvIG1hdGNoIGZpcnN0IHBhcnQgb2YgdGhlIHN0cmluZwpwYXR0ZXJuIDwtICJeW0EtWmEtel0rIgoKIyBVc2UgZ3N1YigpIHRvIHJlcGxhY2UgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIHN0cmluZyB3aXRoIGFuIGVtcHR5IHN0cmluZwpzYW1wbGUubGV2ZWxzLm5ldyA8LSBnc3ViKHBhdHRlcm4sICIiLCBzYW1wbGUubGV2ZWxzKQoKIyBFeHRyYWN0IEIxLCBCMiwgQjMgZnJvbSBuZXcgdmVjdG9yCmJhdGNoIDwtIGdzdWIoIi4qQiIsICJCIiwgc2FtcGxlLmxldmVscy5uZXcpCgpTZXVyYXRfUGFyc2UxMnNhbXBsZSA8LSBhbm5vdGF0ZShTZXVyYXRfUGFyc2UxMnNhbXBsZSwgYW5ub3RhdGlvbnMgPSBiYXRjaCwgdG9fbGFiZWwgPSAic2FtcGxlIixhbm5vdGF0aW9uX25hbWUgPSAiQmF0Y2giKQoKdGFibGUoU2V1cmF0X1BhcnNlMTJzYW1wbGUkQmF0Y2gpCnRhYmxlKFNldXJhdF9QYXJzZTEyc2FtcGxlJEJhdGNoLFNldXJhdF9QYXJzZTEyc2FtcGxlJHNhbXBsZSkKCiMgYWRkIHRoZSBjZWxsIGxpbmUgbmFtZQojIHNhbXBsZSB2ZWN0b3IgaXMgc3RpbGwgdGhlIGlucHV0IHZlY3RvcgojIERlZmluZSByZWd1bGFyIGV4cHJlc3Npb24gdG8gcmVtb3ZlIEIxLCBCMiwgYW5kIEIzCnBhdHRlcm4gPC0gIkJbMS0zXSQiCgojIFVzZSBnc3ViKCkgdG8gcmVtb3ZlIEIxLCBCMiwgYW5kIEIzIGZyb20gb3JpZ2luYWwgdmVjdG9yCnNhbXBsZS5sZXZlbHMubmV3IDwtIGdzdWIocGF0dGVybiwgIiIsIHNhbXBsZS5sZXZlbHMpCgojIEV4dHJhY3Qgc3RhcnRpbmcgdmFsdWVzIGZyb20gbmV3IHZlY3RvcgppcHNjbGluZSA8LSBnc3ViKCJCWzEtM10kIiwgIiIsIHNhbXBsZS5sZXZlbHMubmV3KQppcHNjbGluZQoKU2V1cmF0X1BhcnNlMTJzYW1wbGUgPC0gYW5ub3RhdGUoU2V1cmF0X1BhcnNlMTJzYW1wbGUsIGFubm90YXRpb25zID0gaXBzY2xpbmUsIHRvX2xhYmVsID0gInNhbXBsZSIsYW5ub3RhdGlvbl9uYW1lID0gIklQU0NfTGluZSIpCgp0YWJsZShTZXVyYXRfUGFyc2UxMnNhbXBsZSRJUFNDX0xpbmUpCnRhYmxlKFNldXJhdF9QYXJzZTEyc2FtcGxlJElQU0NfTGluZSxTZXVyYXRfUGFyc2UxMnNhbXBsZSRzYW1wbGUpCgojIGFkZCBkaXNlYXNlIHN0YXR1cwojIHdlIG5lZWQgdG8ga25vdyB0aGUgb3JkZXIgb2YgdGhlIGxpbmVzCgpJZGVudHMoU2V1cmF0X1BhcnNlMTJzYW1wbGUpIDwtICJJUFNDX0xpbmUiCmxpbmUubGV2ZWxzIDwtIGxldmVscyhTZXVyYXRfUGFyc2UxMnNhbXBsZSkKbGluZS5sZXZlbHMKClBEc3RhdHVzIDwtIGMoIlBEIiwiUEQiLCJDb24iLCJDb24iKSAgIyBpZiBURDA3IGFuZCAyOTY1IGFyZSBQRCBsaW5lcyBhbmQgVEQyMiBhbmQgMzQ0OCBhcmUgY29udHJvbCBsaW5lcwpTZXVyYXRfUGFyc2UxMnNhbXBsZSA8LSBhbm5vdGF0ZShTZXVyYXRfUGFyc2UxMnNhbXBsZSwgYW5ub3RhdGlvbnMgPSBQRHN0YXR1cywgdG9fbGFiZWwgPSAiSVBTQ19MaW5lIixhbm5vdGF0aW9uX25hbWUgPSAiRGlzZWFzZVN0YXR1cyIpCgp0YWJsZShTZXVyYXRfUGFyc2UxMnNhbXBsZSREaXNlYXNlU3RhdHVzKQoKIAp0YWJsZShTZXVyYXRfUGFyc2UxMnNhbXBsZSREaXNlYXNlU3RhdHVzLFNldXJhdF9QYXJzZTEyc2FtcGxlJElQU0NfTGluZSkKCnRhYmxlKFNldXJhdF9QYXJzZTEyc2FtcGxlJEJhdGNoLFNldXJhdF9QYXJzZTEyc2FtcGxlJElQU0NfTGluZSkKCgoKCmBgYAoKClNhdmUgaW5mbyAKYGBge3J9CnNhdmVSRFMoU2V1cmF0X1BhcnNlMTJzYW1wbGUsICJQYXJzZTEyc2FtcGxlNGxpbmVzM2JhdGNoSnVseTcuUkRTIikKCnNldSA8LSBTZXVyYXRfUGFyc2UxMnNhbXBsZQpybShTZXVyYXRfUGFyc2UxMnNhbXBsZSkKCiMgcGxvdHMgb2YgaW4gYSBkaWZmZXJlbnQgd29ya2Jvb2sgZm9yIHRoZSBwcmUgYWxpZ25lZCBkYXRhCgpgYGAKCkFsaWduIHRoZSBjZWxsIGxpbmVzIGFuZCBiYXRjaGVzLCB3ZSB3aWxsIGFsaWduIGFjcm9zcyB0aGUgMTIgc2FtcGxlcwoKYGBge3J9CiMgbWFrZSBhIGxpc3Qgb2Ygc2V1cmF0IG9iamVjdHMgYnkgb3VyIGNlbGwgdHlwZSB2YXJpYWJsZQpzdWJsaXN0IDwtIFNwbGl0T2JqZWN0KHNldSwgc3BsaXQuYnkgPSAic2FtcGxlIikKIyBub3JtYWxpemUgYW5kIGZpbmQgdmFyaWFibGUgZmVhdHVyZXMKZm9yIChpIGluIDE6bGVuZ3RoKHN1Ymxpc3QpKXsKICBzdWJsaXN0W1tpXV0gPC0gTm9ybWFsaXplRGF0YShzdWJsaXN0W1tpXV0sIHZlcmJvc2UgPSBGQUxTRSkKICBzdWJsaXN0W1tpXV0gPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc3VibGlzdFtbaV1dLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIpCn0KIyBDcmVhdGUgYW4gZW1wdHkgU2V1cmF0IG9iamVjdCB0byBzdG9yZSB0aGUgaW50ZWdyYXRlZCBkYXRhCiMgVGFrZSB0aGUgZmlyc3QgU2V1cmF0IG9iamVjdCBmcm9tIHRoZSBsaXN0IGFzIHRoZSBzdGFydGluZyBwb2ludAppbnRlZ3JhdGVkX3NldXJhdCA8LSBzdWJzZXQoc3VibGlzdFtbMV1dKQoKCiMgSXRlcmF0ZSBvdmVyIHRoZSBsaXN0IG9mIFNldXJhdCBvYmplY3RzCmZvciAoaSBpbiAxOmxlbmd0aChzdWJsaXN0KSkgewogICMgUmVuYW1lIHRoZSAnb3JpZy5pZGVudCcgbWV0YWRhdGEgaW5zaWRlIHRoZSBzZXVyYXQgb2JqZWN0IHRvIG1hdGNoIHRoZSBvYmplY3QgbmFtZSBpbiB0aGUgbGlzdAogIHN1Ymxpc3RbW2ldXSRvcmlnLmlkZW50IDwtIG5hbWVzKHN1Ymxpc3QpW2ldCgp9CgpzYW1wbGUubGlzdCA8LSBzdWJsaXN0CmZvciAoaSBpbiAxOmxlbmd0aChzYW1wbGUubGlzdCkpIHsKICAjIE5vcm1hbGl6ZSBhbmQgc2NhbGUgdGhlIGRhdGEKICBzYW1wbGUubGlzdFtbaV1dIDwtIE5vcm1hbGl6ZURhdGEoc2FtcGxlLmxpc3RbW2ldXSwgdmVyYm9zZSA9IEZBTFNFKQogIHNhbXBsZS5saXN0W1tpXV0gPC0gU2NhbGVEYXRhKHNhbXBsZS5saXN0W1tpXV0sIHZlcmJvc2UgPSBGQUxTRSkKICAjIEZpbmQgdmFyaWFibGUgZmVhdHVyZXMKICBzYW1wbGUubGlzdFtbaV1dIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNhbXBsZS5saXN0W1tpXV0sIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IikKICAjIEdldCB0aGUgdmFyaWFibGUgZmVhdHVyZXMKICB2YXJpYWJsZV9mZWF0dXJlcyA8LSBWYXJpYWJsZUZlYXR1cmVzKHNhbXBsZS5saXN0W1tpXV0pCiAgIyBSdW4gUENBIHdpdGggdGhlIHZhcmlhYmxlIGZlYXR1cmVzCiAgc2FtcGxlLmxpc3RbW2ldXSA8LSBSdW5QQ0Eoc2FtcGxlLmxpc3RbW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBucGNzID0gMzAsIGZlYXR1cmVzID0gdmFyaWFibGVfZmVhdHVyZXMpCn0KCmludC5hbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBzYW1wbGUubGlzdCwgZGltcyA9IDE6MzAsIHJlZHVjdGlvbiA9ICJycGNhIikKaW50ZWdyYXRlZF9zZXVyYXQgPC0gSW50ZWdyYXRlRGF0YShhbmNob3JzZXQgPSBpbnQuYW5jaG9ycywgIGRpbXMgPSAxOjMwKQojIAojIG11c3Qgc2V0IHRoZSBrIHdlaWdodCB0byB0aGUgbG93ZXN0IGNlbGwgY291bnQgCiMgaW4gdGhlIHBhcnNlIHNhbXBsZSB3ZSBoYXZlIG92ZXIgMTUzMCBjZWxscyBpbiB0aGUgc21hbGxlc3QgY291bnQgc28gd2UgZG9uJ3QgaGF2ZSB0byBjaGFuZ2UgdGhlIGsgZnJvbSB0aGUgMTAwIGRlZmF1bHQKCgoKCmBgYAoKCk5vdyB3ZSBuZWVkIHRvIHJ1biB0aGUgd29ya2Zsb3cgb24gdGhlIGludGVncmF0ZWQgb2JqZWN0CgpgYGB7cn0KRGVmYXVsdEFzc2F5KGludGVncmF0ZWRfc2V1cmF0KSA8LSAiaW50ZWdyYXRlZCIKaW50ZWdyYXRlZF9zZXVyYXQgPC0gU2NhbGVEYXRhKGludGVncmF0ZWRfc2V1cmF0LCB2ZXJib3NlID0gRkFMU0UpCiMgb25seSB0aGUgaW50ZWdyYXRlZCBmZWF0dXJlcyB3aWxsIGJlIHRoZSBwY2EgaW5wdXQKCmludGVncmF0ZWRfc2V1cmF0IDwtIFJ1blBDQShpbnRlZ3JhdGVkX3NldXJhdCwgbnBjcyA9IDIwLCB2ZXJib3NlID0gRkFMU0UpCmludGVncmF0ZWRfc2V1cmF0IDwtIFJ1blVNQVAoaW50ZWdyYXRlZF9zZXVyYXQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCwgbi5uZWlnaGJvcnMgPSA4MSkKCmBgYAoKSGF2ZSBhIGxvb2sgYXQgdGhlIG5ldyBVTUFQCgpgYGB7cn0KRGltUGxvdChpbnRlZ3JhdGVkX3NldXJhdCwgZ3JvdXAuYnkgPSAnc2FtcGxlJykKRGltUGxvdChpbnRlZ3JhdGVkX3NldXJhdCwgZ3JvdXAuYnkgPSAnQmF0Y2gnKQpEaW1QbG90KGludGVncmF0ZWRfc2V1cmF0LCBncm91cC5ieSA9ICdEaXNlYXNlU3RhdHVzJykKRGltUGxvdChpbnRlZ3JhdGVkX3NldXJhdCwgZ3JvdXAuYnkgPSAnSVBTQ19MaW5lJykKCgoKYGBgCgpgYGB7cn0KIyBzYXZlUkRTKGludGVncmF0ZWRfc2V1cmF0LCAiSW50ZWdyYXRlZDEyc2FtcGxlcy5SRFMiKQojIHNldHdkKCJ+L0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BhcnNlRXhhbXBsZS9FeHBlcmltZW50MS1taW5pMTIiKQppbnRlZ3JhdGVkX3NldXJhdCA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QYXJzZUV4YW1wbGUvRXhwZXJpbWVudDEtbWluaTEyL0ludGVncmF0ZWQxMnNhbXBsZXMuUkRTIikKCmBgYAoKRmluZCBuZXcgY2x1c3RlcnMKCmBgYHtyfQpEZWZhdWx0QXNzYXkoaW50ZWdyYXRlZF9zZXVyYXQpIDwtICJpbnRlZ3JhdGVkIgppbnRlZ3JhdGVkX3NldXJhdCA8LSBGaW5kTmVpZ2hib3JzKGludGVncmF0ZWRfc2V1cmF0LCBkaW1zID0gMToyMCwgay5wYXJhbSA9IDgxKQppbnRlZ3JhdGVkX3NldXJhdCA8LSBGaW5kQ2x1c3RlcnMoaW50ZWdyYXRlZF9zZXVyYXQsIHJlc29sdXRpb24gPSBjKDAsMC4zLDAuNiwxKSApCgpgYGAKCmBgYHtyfQpsaWJyYXJ5KGNsdXN0cmVlKQpjbHVzdHJlZShpbnRlZ3JhdGVkX3NldXJhdCkKCgpgYGAKCmBgYHtyfQoKRGltUGxvdChpbnRlZ3JhdGVkX3NldXJhdCwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuMyIpCkRpbVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4wLjYiKQoKYGBgCmBgYHtyfQpEaW1QbG90KGludGVncmF0ZWRfc2V1cmF0LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC4zIiwgc3BsaXQuYnkgPSAiRGlzZWFzZVN0YXR1cyIpCgpgYGAKYGBge3J9CnRhYmxlKGludGVncmF0ZWRfc2V1cmF0JERpc2Vhc2VTdGF0dXMpCgpgYGAKCgoKCkFubm90YXRlIGNsdXN0ZXJzIHJlcyAwLjMKCmBgYHtyfQoKSWRlbnRzKGludGVncmF0ZWRfc2V1cmF0KSA8LSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuMyIKQ2x1c3Rlck1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoaW50ZWdyYXRlZF9zZXVyYXQsIG9ubHkucG9zID0gVFJVRSkKd3JpdGUuY3N2KENsdXN0ZXJNYXJrZXJzLCAiY2x1c3Rlck1hcmtlcnNyZXMwM0ludGVncmF0ZWQuY3N2IikKCmBgYAoKCgpgYGB7cn0KbGlicmFyeShlbnJpY2hSKQpzZXRFbnJpY2hyU2l0ZSgiRW5yaWNociIpICMgSHVtYW4gZ2VuZXMKIyBsaXN0IG9mIGFsbCB0aGUgZGF0YWJhc2VzCiMgZ2V0IHRoZSBwb3NzaWJsZSBsaWJyYXJpZXMKZGJzIDwtIGxpc3RFbnJpY2hyRGJzKCkKCiMgdGhpcyB3aWxsIGxpc3QgdGhlIHBvc3NpYmxlIGxpYnJhcmllcwpkYnMKCiMgc2VsZWN0IGxpYnJhcmllcyB3aXRoIGNlbGwgdHlwZXMKZGIgPC0gYygnQ2VsbE1hcmtlcl9BdWdtZW50ZWRfMjAyMScsJ0F6aW11dGhfQ2VsbF9UeXBlc18yMDIxJykKCiMgZnVuY3Rpb24gZm9yIGEgcXVpY2sgbG9vawpjaGVja0NlbGx0eXBlcyA8LSBmdW5jdGlvbihjbHVzdGVyX251bSA9IDApewogIGNsdXN0ZXJYIDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSBjbHVzdGVyX251bSAmIGF2Z19sb2cyRkMgPiAwLjI1KQogIGdlbmVzIDwtIGNsdXN0ZXJYJGdlbmUKICAjIHRoZSBjZWxsIHR5cGUgbGlicmFyaWVzCiAgIyBnZXQgdGhlIHJlc3VsdHMgZm9yIGVhY2ggbGlicmFyeQogIGNsdXN0ZXJYLmNlbGwgPC0gZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gZGIpCiAgIyB2aXN1YWxpemUgdGhlIHJlc3VsdHMKcHJpbnQocGxvdEVucmljaChjbHVzdGVyWC5jZWxsW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiLCB0aXRsZSA9ICdDZWxsTWFya2VyX0F1Z21lbnRlZF8yMDIxJykpCnByaW50KHBsb3RFbnJpY2goY2x1c3RlclguY2VsbFtbMl1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIiwgdGl0bGUgPSAnQXppbXV0aF9DZWxsX1R5cGVzXzIwMjEnKSkKCn0KCmBgYApgYGB7cn0KI2hlYXRtYXAgb2YgdG9wIG1hcmtlcnMKdG9wMyA8LSBDbHVzdGVyTWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG49Mywgd3QgPWF2Z19sb2cyRkMpCkRvSGVhdG1hcChpbnRlZ3JhdGVkX3NldXJhdCwgZmVhdHVyZXMgPSB0b3AzJGdlbmUsIHNpemUgPSAzLCBhbmdsZSA9IDkwLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC4zIikKCgpgYGAKCmBgYHtyfQp0YWJsZShDbHVzdGVyTWFya2VycyRjbHVzdGVyKQpgYGAKCgoKCkNoZWNrIGVhY2ggY2x1c3RlciBxdWlja2x5CgpgYGB7cn0KY2hlY2tDZWxsdHlwZXMoY2x1c3Rlcl9udW0gPSAzKQoKYGBgCgpMb29rIGF0IHNvbWUgZXhwcmVzc2lvbiBsaXN0cwoKYGBge3J9CgpkYV9uZXVyb25zIDwtIGMoIlRIIiwiU0xDNkEzIiwiU0xDMThBMiIsIlNPWDYiLCJORE5GIiwiU05DRyIsIkFMREgxQTEiLCJDQUxCMSIsIlRBQ1IyIiwiU0xDMTdBNiIsIlNMQzMyQTEiLCJPVFgyIiwiR1JQIiwiTFBMIiwiQ0NLIiwiVklQIikKTlBDX29yU3RlbUxpa2UgPC0gYygiRENYIiwiTkVVUk9EMSIsIlRCUjEiLCJQQ05BIiwiTUtJNjciLCJTT1gyIiwiTkVTIiwiUEFYNiIsIk1BU0gxIikKbWF0dXJlX25ldXJvbnMgPSBjKCJSQkZPWDMiLCJTWVAiLCJETEc0NSIsIlZBTVAxIiwiVkFNUDIiLCJUVUJCMyIsIlNZVDEiLCJCU04iLCJIT01FUjEiLCJTTEMxN0E2IikKZXhjaXRhdG9yeV9uZXVyb25zID0gYygiR1JJQTIiLCJHUklBMSIsIkdSSUE0IiwiR1JJTjEiLCJHUklOMkIiLCJHUklOMkEiLCJHUklOM0EiLCJHUklOMyIsIkdSSVAxIiwiQ0FNSzJBIikKaW5oYml0b3J5X25ldXJvbnMgPSBpbmggPSBjKCJHQUQxIiwiR0FEMiIsICJHQVQxIiwiUFZBTEIiLCJHQUJSMiIsIkdBQlIxIiwiR0JSUjEiLCJHQUJSQjIiLCJHQUJSQjEiLCJHQUJSQjMiLCJHQUJSQTYiLCJHQUJSQTEiLCJHQUJSQTQiLCJUUkFLMiIpCmFzdHJvY3l0ZXMgPC0gYygiR0ZBUCIsIlMxMDBCIiwiQVFQNCIsIkFQT0UiLCAiU09YOSIsIlNMQzFBMyIpCm9saWdvZGVuZHJvY3l0ZXMgPC0gYygiTUJQIiwiTU9HIiwiT0xJRzEiLCJPTElHMiIsIlNPWDEwIikKb3BjIDwtIApyYWRpYWxfZ2xpYSA8LSBjKCJQVFBSQyIsIkFJRjEiLCJBREdSRTEiLCAiVklNIiwgIlROQyIsIlBUUFJaMSIsIkZBTTEwN0EiLCJIT1BYIiwiTElGUiIsCiAgICAgICAgICAgICAgIklUR0I1IiwiSUw2U1QiLCJTTEMxQTMiKQplcGl0aGVsaWFsIDwtIGMoIkhFUzEiLCJIRVM1IiwiU09YMiIsIlNPWDEwIiwiTkVTIiwiQ0RIMSIsIk5PVENIMSIpCgptaWNyb2dsaWEgPC0gYygiSUJBMSIsIlAyUlkxMiIsIlAyUlkxMyIsIlRSRU0xMTkiLCAiR1BSMzQiLCJTSUdMRUNIIiwiVFJFTTIiLAogICAgICAgICAgICAgICAiQ1gzQ1IxIiwiRkNSTFMiLCJPTEZNTDMiLCJIRVhCIiwiVEdGQlIxIiwgIlNBTEwxIiwiTUVSVEsiLAogICAgICAgICAgICAgICAiUFJPUzEiKQoKZmVhdHVyZXNfbGlzdCA8LSBjKCJNS0k2NyIsIlNPWDIiLCJQT1U1RjEiLCJETFgyIiwiUEFYNiIsIlNPWDkiLCJIRVMxIiwiTkVTIiwiUkJGT1gzIiwiTUFQMiIsIk5DQU0xIiwiQ0QyNCIsIkdSSUEyIiwiR1JJTjJCIiwiR0FCQlIxIiwiR0FEMSIsIkdBRDIiLCJHQUJSQTEiLCJHQUJSQjIiLCJUSCIsIkFMREgxQTEiLCJMTVgxQiIsIk5SNEEyIiwiQ09SSU4iLCJDQUxCMSIsIktDTko2IiwiQ1hDUjQiLCJJVEdBNiIsIlNMQzFBMyIsIkNENDQiLCJBUVA0IiwiUzEwMEIiLCAiUERHRlJBIiwiT0xJRzIiLCJNQlAiLCJDTEROMTEiLCJWSU0iLCJWQ0FNMSIpCgpzaG9ydF9saXN0IDwtIGMoIk1LSTY3IiwiU09YOSIsIkhFUzEiLCJORVMiLCJETFgyIiwiUkJGT1gzIiwiTUFQMiIsIlRIIiwiQ0FMQjEiLCJLQ05KNiIsIlNMQzFBMyIsIkNENDQiLCJBUVA0IiwiUzEwMEIiLCJPTElHMiIsIk1CUCIsIlZJTSIpCgpgYGAKCgpgYGB7cn0KSWRlbnRzKGludGVncmF0ZWRfc2V1cmF0KSA8LSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuMyIKCmZvciAoaSBpbiBkYV9uZXVyb25zKSB7CiAgcHJpbnQoRmVhdHVyZVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIGZlYXR1cmVzID0gaSwgbWluLmN1dG9mZiA9ICdxMScsIG1heC5jdXRvZmYgPSAncTk3JywgbGFiZWwgPSBUUlVFKSkKfQoKYGBgCgpgYGB7cn0KSWRlbnRzKGludGVncmF0ZWRfc2V1cmF0KSA8LSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuMyIKCmZvciAoaSBpbiBOUENfb3JTdGVtTGlrZSkgewogIHByaW50KEZlYXR1cmVQbG90KGludGVncmF0ZWRfc2V1cmF0LCBmZWF0dXJlcyA9IGksIG1pbi5jdXRvZmYgPSAncTEnLCBtYXguY3V0b2ZmID0gJ3E5NycsIGxhYmVsID0gVFJVRSkpCn0KYGBgCgpgYGB7cn0KSWRlbnRzKGludGVncmF0ZWRfc2V1cmF0KSA8LSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuMyIKCmZvciAoaSBpbiBhc3Ryb2N5dGVzKSB7CiAgcHJpbnQoRmVhdHVyZVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIGZlYXR1cmVzID0gaSwgbWluLmN1dG9mZiA9ICdxMScsIG1heC5jdXRvZmYgPSAncTk3JywgbGFiZWwgPSBUUlVFKSkKfQpgYGAKCmBgYHtyfQpJZGVudHMoaW50ZWdyYXRlZF9zZXVyYXQpIDwtICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC4zIgoKZm9yIChpIGluIHJhZGlhbF9nbGlhKSB7CiAgcHJpbnQoRmVhdHVyZVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIGZlYXR1cmVzID0gaSwgbWluLmN1dG9mZiA9ICdxMScsIG1heC5jdXRvZmYgPSAncTk3JywgbGFiZWwgPSBUUlVFKSkKfQoKYGBgCgoKYGBge3J9CklkZW50cyhpbnRlZ3JhdGVkX3NldXJhdCkgPC0gImludGVncmF0ZWRfc25uX3Jlcy4wLjMiCgpmb3IgKGkgaW4gbWF0dXJlX25ldXJvbnMpIHsKICBwcmludChGZWF0dXJlUGxvdChpbnRlZ3JhdGVkX3NldXJhdCwgZmVhdHVyZXMgPSBpLCBtaW4uY3V0b2ZmID0gJ3ExJywgbWF4LmN1dG9mZiA9ICdxOTcnLCBsYWJlbCA9IFRSVUUpKQp9CgoKYGBgCgpgYGB7cn0KCklkZW50cyhpbnRlZ3JhdGVkX3NldXJhdCkgPC0gImludGVncmF0ZWRfc25uX3Jlcy4wLjMiCgpmb3IgKGkgaW4gZXhjaXRhdG9yeV9uZXVyb25zKSB7CiAgcHJpbnQoRmVhdHVyZVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIGZlYXR1cmVzID0gaSwgbWluLmN1dG9mZiA9ICdxMScsIG1heC5jdXRvZmYgPSAncTk3JywgbGFiZWwgPSBUUlVFKSkKfQoKCmBgYApBZGQgYW5ub3RhdGlvbnMgLSBmaXJzdCBwYXNzCk5QQy1zdGVtCk5QQy1nbGlhCk5QQy1TT1g2Ck5ldXJvbnMtR2x1dApQcm9nZW5pdG9ycy1kaXYKTlBDLVNPWDItT1hULWZpYnJvCk5ldXJhbC1TdGVtCnN0ZW0gY2VsbApOZXVyb24tR0FCQQpOZXVyb24tZXBpdGhlbGlhbAoKYGBge3J9CmNlbGx0eXBlczEgPC0gYygiTlBDLXN0ZW0iLCJOUEMtZ2xpYSIsIk5QQy1TT1g2IiwiTmV1cm9ucy1HbHV0IiwiUHJvZ2VuaXRvcnMtZGl2IiwKICAgICAgICAgICAgICAgICJOUEMtZmlicm8iLCJOZXVyYWwtU3RlbSIsIlN0ZW0iLCJOZXVyb25zLUdBQkEiLCJOZXVyYWwtZXBpIikgIAppbnRlZ3JhdGVkX3NldXJhdCA8LSBhbm5vdGF0ZShpbnRlZ3JhdGVkX3NldXJhdCwgYW5ub3RhdGlvbnMgPSBjZWxsdHlwZXMxLCB0b19sYWJlbCA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC4zIixhbm5vdGF0aW9uX25hbWUgPSAiQ2VsbHR5cGVzMSIpCgpEaW1QbG90KGludGVncmF0ZWRfc2V1cmF0LCBsYWJlbCA9IFRSVUUpCgpgYGAKCmBgYHtyfQoKY2VsbHR5cGVzMiA8LSBjKCJOUEMiLCJOUEMiLCJOUEMiLCJOZXVyb25zIiwiTlBDIiwKICAgICAgICAgICAgICAgICJOUEMiLCJOUEMiLCJTdGVtIiwiTmV1cm9ucyIsIkVwaXRoZWxpYWwiKSAgCgppbnRlZ3JhdGVkX3NldXJhdCA8LSBhbm5vdGF0ZShpbnRlZ3JhdGVkX3NldXJhdCwgYW5ub3RhdGlvbnMgPSBjZWxsdHlwZXMyLCB0b19sYWJlbCA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC4zIixhbm5vdGF0aW9uX25hbWUgPSAiQ2VsbHR5cGVzMiIpCgpEaW1QbG90KGludGVncmF0ZWRfc2V1cmF0LCBsYWJlbCA9IFRSVUUpCgpgYGAKCmBgYHtyfQoKCkRpbVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIHNwbGl0LmJ5ID0gIkRpc2Vhc2VTdGF0dXMiKQpEaW1QbG90KGludGVncmF0ZWRfc2V1cmF0LCBzcGxpdC5ieSA9ICJEaXNlYXNlU3RhdHVzIiwgZ3JvdXAuYnkgPSAiQ2VsbHR5cGVzMSIpCgoKYGBgCgpgYGB7cn0KY2VsbHR5cGVzMyA8LSBjKCJOUEMiLCJOUEMiLCJOUEMiLCJOZXVyb25zIiwiTlBDLWRpdiIsCiAgICAgICAgICAgICAgICAiTmV1cm8tTlBDIiwiTmV1cmFsLVN0ZW0iLCJTdGVtIiwiTmV1cm9ucyIsIk5ldXJhbC1lcGkiKSAgCmludGVncmF0ZWRfc2V1cmF0IDwtIGFubm90YXRlKGludGVncmF0ZWRfc2V1cmF0LCBhbm5vdGF0aW9ucyA9IGNlbGx0eXBlczMsIHRvX2xhYmVsID0gImludGVncmF0ZWRfc25uX3Jlcy4wLjMiLGFubm90YXRpb25fbmFtZSA9ICJDZWxsdHlwZXMzIikKCkRpbVBsb3QoaW50ZWdyYXRlZF9zZXVyYXQsIGxhYmVsID0gVFJVRSkKYGBgCmBgYHtyfQp0YWJsZShpbnRlZ3JhdGVkX3NldXJhdCRJUFNDX0xpbmUpCmBgYAoKCgpERUcgaW4gY2VsbCB0eXBlcyAzIGdyb3VwcwoKYGBge3J9CkRlZmF1bHRBc3NheShpbnRlZ3JhdGVkX3NldXJhdCkgPC0gIlJOQSIKSWRlbnRzKGludGVncmF0ZWRfc2V1cmF0KSA8LSAiQ2VsbHR5cGVzMyIKbGV2ZWxzKGludGVncmF0ZWRfc2V1cmF0KQpzZXVfc3ViIDwtIHN1YnNldChpbnRlZ3JhdGVkX3NldXJhdCwgaWRlbnRzID0gIk5ldXJvbnMiKQpkaW0oc2V1X3N1YikKdGFibGUoc2V1X3N1YiRJUFNDX0xpbmUpCnNldV9zdWIgPC0gU2NhbGVEYXRhKHNldV9zdWIpCnNldV9zdWIgPC0gTm9ybWFsaXplRGF0YShzZXVfc3ViKQoKSWRlbnRzKHNldV9zdWIpIDwtICJEaXNlYXNlU3RhdHVzIgpsZXZlbHMoc2V1X3N1YikKREdFIDwtIEZpbmRNYXJrZXJzKHNldV9zdWIsIGlkZW50LjEgPSAiUEQiLCBpZGVudC4yID0gIkNvbiIpCkRpbVBsb3Qoc2V1X3N1YiwgZ3JvdXAuYnkgPSAiRGlzZWFzZVN0YXR1cyIpCgoKYGBgCmBgYHtyfQp0YWJsZShzZXVfc3ViJERpc2Vhc2VTdGF0dXMpCmBgYAoKCk5ldXJvbnMgREdFIHZvbGNhbm8gcGxvdAoKYGBge3IsIGZpZy5oZWlnaHQ9IDN9CgpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKRW5oYW5jZWRWb2xjYW5vKERHRSwKICAgIGxhYiA9IHJvd25hbWVzKERHRSksCiAgICAjeGxpbSA9IGMoLTAuMjUsMC4yNSksCiAgICB4ID0gJ2F2Z19sb2cyRkMnLAogICAgeSA9ICdwX3ZhbF9hZGonLAogICAgcEN1dG9mZiA9IDAuMDAwMDAxLAogICAgRkNjdXRvZmYgPSAxLAogICAgcG9pbnRTaXplID0gMy4wLAogICAgbGFiU2l6ZSA9IDYuMCkKCgoKYGBgCgpgYGB7cn0KZnQgPC0gYygiTUdBVDRDIiwiVEJSMSIsIlNMQzRBMTAiLCJSRUxOIiwiUFRQUkQiLAogICAgICAgICJHUEM1IiwiU0lNMSIsIk9ORUNVVDIiLCJFQkYxIiwiTE1YMUEiKQoKRG90UGxvdChzZXVfc3ViLCBmZWF0dXJlcyA9IGZ0KSArUm90YXRlZEF4aXMoKQoKaGVhZChER0UpCiMgZmlsdGVyIGZvciBzaWduaWZpY2FudCBwdmFsdWVzCkRHRS5mdCA8LSBER0UgJT4lIGZpbHRlcihwX3ZhbF9hZGogPD0gMC4wMSkKdXAgPC0gREdFLmZ0ICU+JSBmaWx0ZXIoYXZnX2xvZzJGQyA+IDAuMSkKZG93biA8LSBER0UuZnQgJT4lIGZpbHRlcihhdmdfbG9nMkZDIDwgLTAuMSkKCgpgYGAKCgoKCgpDcmVhdGUgYSBzdW0gb2YgY291bnRzIGRhdGEgdGFibGUgCgpgYGB7cn0Kc3VtX2NvdW50cyA8LSBBZ2dyZWdhdGVFeHByZXNzaW9uKGludGVncmF0ZWRfc2V1cmF0LCBhc3NheSA9ICJSTkEiLCBncm91cC5ieSA9ICJzYW1wbGUiLCBhZGQuaWRlbnQgPSAic2FtcGxlIikKIyB0aGlzIHNlZW1zIHRvIGdyb3VwIGJ5IHRoZSBncm91cCBhbmQgdGhlIGFjdGl2ZSBpZGVudCB0b2dldGhlcgoKCgpjb2xuYW1lcyhpbnRlZ3JhdGVkX3NldXJhdEBtZXRhLmRhdGEpCmRpbShzdW1fY291bnRzJFJOQSkKc3VtX2NvdW50c19kZiA8LSBhcy5kYXRhLmZyYW1lKHN1bV9jb3VudHMkUk5BKQpkaW0oc3VtX2NvdW50c19kZikKd3JpdGUuY3N2KHN1bV9jb3VudHNfZGYsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QYXJzZUV4YW1wbGUvRXhwZXJpbWVudDEtbWluaTEyL1N1bUNvdW50c19JbnRlZ3JhdGVkX2J5X3NhbXBsZV9jZWxsdHlwZS5jc3YiKQpzdW1fY291bnRzX2RmWzE6NCwxOjVdCgoKCmBgYAoKVHJ5IHRvIHNlcGFyYXRlbHkgdmFyaWFibGVzIGluIHRoZSBhZ2dyZWdhdGlvbgoKYGBge3J9CmNvbG5hbWVzKGludGVncmF0ZWRfc2V1cmF0QG1ldGEuZGF0YSkKCnN1bV9jb3VudHMgPC0gQWdncmVnYXRlRXhwcmVzc2lvbihpbnRlZ3JhdGVkX3NldXJhdCwgYXNzYXkgPSAiUk5BIiwgZ3JvdXAuYnkgPSBjKCJCYXRjaCIsIklQU0NfTGluZSIsIkRpc2Vhc2VTdGF0dXMiKSkKIyB0aGlzIHNlZW1zIHRvIGdyb3VwIGJ5IHRoZSBncm91cCBhbmQgdGhlIGFjdGl2ZSBpZGVudCB0b2dldGhlcgoKCgpjb2xuYW1lcyhpbnRlZ3JhdGVkX3NldXJhdEBtZXRhLmRhdGEpCmRpbShzdW1fY291bnRzJFJOQSkKc3VtX2NvdW50c19kZiA8LSBhcy5kYXRhLmZyYW1lKHN1bV9jb3VudHMkUk5BKQpkaW0oc3VtX2NvdW50c19kZikKCiMgYWxsIGNlbGwgdHlwZXMgYXJlIGludGVncmF0ZWQKCndyaXRlLmNzdihzdW1fY291bnRzX2RmLCAiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGFyc2VFeGFtcGxlL0V4cGVyaW1lbnQxLW1pbmkxMi9TdW1Db3VudHNfSW50ZWdyYXRlZF9hbGxDZWxsdHlwZXNfMTJzYW1wbGVzLmNzdiIpCgoKYGBgCgoKVHJ5IHRvIG1ha2UgdGhlIE1EUyBwbG90cyBhbmQgdGhlIERFU2VxMiBER0UKCmBgYHtyfQpsaWJyYXJ5KCAiREVTZXEyIiApCmxpYnJhcnkoZ2dwbG90MikKCmBgYAoKUmVhZCBiYWNrIGluIHRoZSBhZ2dyZWdhdGVkIHZhbHVlcyAoZ3JvdXBlZCBieSBzYW1wbGUgZm9yIGFsbCBjbHVzdGVycykKCmBgYHtyfQpkZi5hbGwgPC0gcmVhZC5jc3YoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BhcnNlRXhhbXBsZS9FeHBlcmltZW50MS1taW5pMTIvU3VtQ291bnRzX0ludGVncmF0ZWRfYWxsQ2VsbHR5cGVzXzEyc2FtcGxlcy5jc3YiKQoKaGVhZChkZi5hbGwpCgpgYGAKCgpJIG5lZWQgdG8gcHJlcGFyZSBmb3IgREVHc2VxMgoKYGBge3J9CnJvd25hbWVzKGRmLmFsbCkgPC0gZGYuYWxsJFgKZGYuYWxsIDwtIGRmLmFsbCAlPiUgc2VsZWN0KC0iWCIpCnQuZGYgPC0gdChkZi5hbGwpCnQuZGZbMTozLDE6NV0KCgpgYGAKCgpOb3cgYWRkIHRoZSBtZXRhIGRhdGEKCmBgYHtyfQoKIyBBc3N1bWluZyBkZiBpcyB0aGUgbmFtZSBvZiB5b3VyIGRhdGFmcmFtZQpzYW1wbGUgPC0gYXMuZGF0YS5mcmFtZShyb3duYW1lcyh0LmRmKSkKY29sbmFtZXMoc2FtcGxlKSA8LSAic2FtcGxlIgoKcHJpbnQoc2FtcGxlJHNhbXBsZSkKCiMgQXNzdW1pbmcgdC5kZiBpcyB5b3VyIG9yaWdpbmFsIGRhdGFmcmFtZSB3aXRoIHRoZSAic2FtcGxlIiBjb2x1bW4KCiMgRXh0cmFjdCB2YWx1ZXMgZm9yICJCYXRjaCwiICJMaW5lLCIgYW5kICJEaXNlYXNlU3RhdHVzIiB1c2luZyByZWd1bGFyIGV4cHJlc3Npb25zCnNhbXBsZV9uYW1lcyA8LSBzYW1wbGUkc2FtcGxlCnNhbXBsZV9pbmZvIDwtIHN0cnNwbGl0KHNhbXBsZV9uYW1lcywgIl8iKQpzYW1wbGVfaW5mbyA8LSBkby5jYWxsKHJiaW5kLCBzYW1wbGVfaW5mbykKCiMgQ3JlYXRlIG5ldyBjb2x1bW5zIGZvciAiQmF0Y2gsIiAiTGluZSwiIGFuZCAiRGlzZWFzZVN0YXR1cyIKc2FtcGxlJEJhdGNoIDwtIHNhbXBsZV9pbmZvWywgMV0Kc2FtcGxlJExpbmUgPC0gc2FtcGxlX2luZm9bLCAyXQpzYW1wbGUkRGlzZWFzZVN0YXR1cyA8LSBzYW1wbGVfaW5mb1ssIDNdCgojIERpc3BsYXkgdGhlIHVwZGF0ZWQgZGF0YWZyYW1lCnByaW50KHNhbXBsZSkKCiNub3cgYWRkIHRoZSBtZXRhIGRhdGEgdG8gdGhlIGdlbmUgUk5BIHJlYWQgc3VtIG1hdHJpeAptZXRhLmRmLmFsbCA8LSBjYmluZChzYW1wbGUsIHQuZGYpCgpoZWFkKG1ldGEuZGYuYWxsKQoKYGBgClByZXBhcmUgb2JqZWN0cyBmb3IgREVHc2VxMgoKYGBge3J9CmxpYnJhcnkoICJERVNlcTIiICkKIyB0aGUgaW5wdXQgaXMgYSBkYXRhZnJhbWUgd2l0aCBvbmx5IGV4cHJlc3Npb24gdmFsdWVzIG5vIG1ldGEgZGF0YQojIHRoZSBkYXRhZnJhbWUgZ2V0cyB0cmFuc3Bvc2VkIGJhY2sgc28gdGhlIGluaXRpYWwgREYgYWxsIGlzIGNvcnJlY3QKZGZ0IDwtIGRmLmFsbCAjIGNvbHVtbnMgYXJlIHNhbXBsZXMgYW5kIGdlbmVzIGFyZSByb3dzCgojcHJlcGFyZSB0aGUgZGRzIG9iamVjdCAKIyB3ZSBuZWVkIHRoZSB0cmFuc3Bvc2VkIGRhdGEgZnJhbWUgbm8gbWV0YSBkYXRhCgpkZmkgPC0gbGFwcGx5KGRmdCwgYXMuaW50ZWdlcikKZGZpIDwtIGFzLmRhdGEuZnJhbWUoZGZpKQpyb3duYW1lcyhkZmkpIDwtIHJvd25hbWVzKGRmdCkKCiMgaGVyZSB3ZSBuZWVkIHRoZSBtZXRhIGRhdGEKZGYubWV0YSA8LSBzYW1wbGUKIyBhbmQgd2UgbmVlZCB3aGF0IHZhcmlhYmxlIHRvIGNvbXBhcmUKCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRmaSwgY29sRGF0YSA9IGRmLm1ldGEsIGRlc2lnbiA9IH5EaXNlYXNlU3RhdHVzKQoKIyBJIHJhbiB0aGlzIG9yaWdpbmFsbHkgd2l0aCBhbGwgZGF0YQoKYGBgCmBgYHtyfQojIHNlZSB0aGUgb2JqZWN0CmRkcwpgYGAKTm93IHdlIHJ1biB0aGUgREVTRVEgZnVuY3Rpb24KCmBgYHtyfQpkZHMgPC0gREVTZXEoZGRzKQpgYGAKTG9vayBhdCB0aGUgcmVzdWx0cwoKYGBge3J9CnJlcyA8LSByZXN1bHRzKGRkcykKaGVhZChyZXN1bHRzKGRkcywgdGlkeT0gVFJVRSkpCgpgYGAKCmBgYHtyfQpzdW1tYXJ5KHJlcykKCmBgYApgYGB7ciwgZmlnLmhlaWdodD0gNX0KbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCiAgRW5oYW5jZWRWb2xjYW5vKHJlcywKICAgIGxhYiA9IHJvd25hbWVzKHJlcyksCiAgICB4ID0gJ2xvZzJGb2xkQ2hhbmdlJywKICAgIHkgPSAncHZhbHVlJywKICAgIHRpdGxlID0gJ0FsbCBjZWxsIHR5cGVzIE5QQ3MnLAogICAgcEN1dG9mZiA9IDAuMDAxLAogICAgRkNjdXRvZmYgPSAyLjUsCiAgICBwb2ludFNpemUgPSA1LjAsCiAgICBsYWJTaXplID0gNSwgCiAgICBsZWdlbmRMYWJTaXplID0gMTUsCiAgICBsZWdlbmRJY29uU2l6ZSA9IDIpCgpgYGAKCmBgYHtyfQoKdnNkYXRhIDwtIHZhcmlhbmNlU3RhYmlsaXppbmdUcmFuc2Zvcm1hdGlvbihkZHMpCgpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXA9IkRpc2Vhc2VTdGF0dXMiKQpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXA9IkxpbmUiKQpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXA9IkJhdGNoIikKcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwPSJzYW1wbGUiKQoKYGBgCgpERVNlcTIgYW5hbHlzaXMgZnJvbSB0aGUgY2VsbCB0eXBlIHNlcGFyYXRlIGFnZ3JlZ2F0ZWQgZGF0YQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpkZiA8LSByZWFkLmNzdigiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGFyc2VFeGFtcGxlL0V4cGVyaW1lbnQxLW1pbmkxMi9TdW1Db3VudHNfSW50ZWdyYXRlZF9ieV9zYW1wbGVfY2VsbHR5cGUuY3N2IikKCnJvd25hbWVzKGRmKSA8LSBkZiRYCmRmIDwtIGRmICU+JSBzZWxlY3QoLSJYIikKY29sbmFtZXMoZGYpCgpgYGAKCk1ha2UgdGhlIG1ldGFkYXRhIAoKYGBge3J9CiMgQXNzdW1pbmcgZGYgaXMgeW91ciBvcmlnaW5hbCBkYXRhZnJhbWUKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yICJDZWxsdHlwZSwiICJMaW5lLCIgYW5kICJCYXRjaCIgdXNpbmcgcmVndWxhciBleHByZXNzaW9ucwpjb2xfbmFtZXMgPC0gY29sbmFtZXMoZGYpCm1ldGFfaW5mbyA8LSBzdHJzcGxpdChjb2xfbmFtZXMsICJfIikKbWV0YV9pbmZvIDwtIGRvLmNhbGwocmJpbmQsIG1ldGFfaW5mbykKCiMgU3BsaXQgTGluZSBhbmQgQmF0Y2ggaW5mb3JtYXRpb24KbGluZV9pbmZvIDwtIHN1YnN0cmluZyhtZXRhX2luZm9bLCAyXSwgMSwgbmNoYXIobWV0YV9pbmZvWywgMl0pIC0gMSkKYmF0Y2hfaW5mbyA8LSBzdWJzdHJpbmcobWV0YV9pbmZvWywgMl0sIG5jaGFyKG1ldGFfaW5mb1ssIDJdKSwgbmNoYXIobWV0YV9pbmZvWywgMl0pKQoKIyBDcmVhdGUgdGhlIG1ldGFkYXRhIGRhdGFmcmFtZSBkZi5tZXRhCmRmLm1ldGEgPC0gZGF0YS5mcmFtZSgKICBTYW1wbGUgPSBjb2xfbmFtZXMsCiAgQ2VsbHR5cGUgPSBtZXRhX2luZm9bLCAxXSwKICBMaW5lID0gbGluZV9pbmZvLAogIEJhdGNoID0gYmF0Y2hfaW5mbwopCgojIENyZWF0ZSB0aGUgIkRpc2Vhc2VTdGF0dXMiIGNvbHVtbgpkaXNlYXNlX3N0YXR1cyA8LSBpZmVsc2UoZ3JlcGwoIlREMDd8eDI5NjUiLCBsaW5lX2luZm8pLCAiUEQiLCAiQ29uIikKTWl4MSA8LSBpZmVsc2UoZ3JlcGwoIlREMDd8VEQyMiIsIGxpbmVfaW5mbyksICJBIiwgIkIiKQpNaXgyIDwtIGlmZWxzZShncmVwbCgieDM0NDh8VEQwNyIsIGxpbmVfaW5mbyksICJBIiwgIkIiKQojIENyZWF0ZSB0aGUgbWV0YWRhdGEgZGF0YWZyYW1lIGRmLm1ldGEKZGYubWV0YSA8LSBkYXRhLmZyYW1lKAogIFNhbXBsZSA9IGNvbF9uYW1lcywKICBDZWxsdHlwZSA9IG1ldGFfaW5mb1ssIDFdLAogIExpbmUgPSBsaW5lX2luZm8sCiAgQmF0Y2ggPSBiYXRjaF9pbmZvLAogIERpc2Vhc2VTdGF0dXMgPSBkaXNlYXNlX3N0YXR1cywKICBNaXgxID0gTWl4MSwKICBNaXgyID0gTWl4MgopCgojIERpc3BsYXkgdGhlIG1ldGFkYXRhIGRhdGFmcmFtZQpwcmludChkZi5tZXRhKQoKYGBgCgpOb3cgc2V0IHVwIGZvciB0aGUgREVHCgpgYGB7cn0KbGlicmFyeShERVNlcTIpCiMgdGhlIGlucHV0IGlzIGEgZGF0YWZyYW1lIHdpdGggb25seSBleHByZXNzaW9uIHZhbHVlcyBubyBtZXRhIGRhdGEKIyB0aGUgYWdncmVnYXRlIHNldXJhdCBmdW5jdGlvbiBpcyBhbHJlYWR5IGluIHRoaXMgZm9ybWF0CiMgaG93ZXZlciB0byB1c2Ugb25seSBvbmUgY2VsbCB0eXBlIGl0IG5lZWRzIHRvIGJlIHN1YnNldCBpbiBhZHZhbmNlCiMgaGVyZSBhZ2FpbiBJIHdpbGwgdXNlIGFsbCB0aGUgY2VsbCB0eXBlcwpkZnQgPC0gZGYgIyBjb2x1bW5zIGFyZSBzYW1wbGVzIGFuZCBnZW5lcyBhcmUgcm93cwpkaW0oZGZ0KQojcHJlcGFyZSB0aGUgZGRzIG9iamVjdCAKIyB3ZSBuZWVkIHRoZSB0cmFuc3Bvc2VkIGRhdGEgZnJhbWUgbm8gbWV0YSBkYXRhCgpkZmkgPC0gbGFwcGx5KGRmdCwgYXMuaW50ZWdlcikKZGZpIDwtIGFzLmRhdGEuZnJhbWUoZGZpKQpkaW0oZGZpKQpyb3duYW1lcyhkZmkpIDwtIHJvd25hbWVzKGRmdCkKCiMgaGVyZSB3ZSBuZWVkIHRoZSBtZXRhIGRhdGEKIyB3YXMgY3JlYXRlZCBhYm92ZSA9IGRmLm1ldGEKIyBhbmQgd2UgbmVlZCB3aGF0IHZhcmlhYmxlIHRvIGNvbXBhcmUKCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRmaSwgY29sRGF0YSA9IGRmLm1ldGEsIGRlc2lnbiA9IH5EaXNlYXNlU3RhdHVzKQoKCmBgYAoKCmBgYHtyfQojIHNlZSB0aGUgb2JqZWN0CmRkcwojIHJ1biBEZXFTZXEyCmRkcyA8LSBERVNlcShkZHMpCiMgc2VlIHJlc3VsdHMKcmVzIDwtIHJlc3VsdHMoZGRzKQpoZWFkKHJlc3VsdHMoZGRzLCB0aWR5PSBUUlVFKSkKc3VtbWFyeShyZXMpCgpgYGAKUENBIHBsb3RzCgpgYGB7cn0KdnNkYXRhIDwtIHZhcmlhbmNlU3RhYmlsaXppbmdUcmFuc2Zvcm1hdGlvbihkZHMpCgpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXA9IkRpc2Vhc2VTdGF0dXMiKQpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXA9IkxpbmUiKQpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXA9IkJhdGNoIikKcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwPSJTYW1wbGUiKQpwbG90UENBKHZzZGF0YSwgaW50Z3JvdXAgPSAiQ2VsbHR5cGUiKQoKYGBgCgoKU3Vic2V0IGZ1bGwgZGF0YWZyYW1lIGJ5IGNlbGwgdHlwZQoKCmBgYHtyfQojIEFzc3VtaW5nIGRmLnRyYW5zIGlzIHlvdXIgdHJhbnNwb3NlZCBkYXRhZnJhbWUgYW5kIGRmLm1ldGEgaXMgeW91ciBtZXRhZGF0YSBkYXRhZnJhbWUKCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyeQojbGlicmFyeShERVNlcTIpCgojIEV4dHJhY3QgdW5pcXVlIGNlbGwgdHlwZXMgZnJvbSB0aGUgIkNlbGx0eXBlIiBjb2x1bW4gaW4gZGYubWV0YQpDZWxsdHlwZXMgPC0gdW5pcXVlKGRmLm1ldGEkQ2VsbHR5cGUpCnByaW50KENlbGx0eXBlcykKIyBDcmVhdGUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSBERVNlcSByZXN1bHRzIGZvciBlYWNoIGNlbGwgdHlwZQpsaXN0LnJlc3VsdHMgPC0gbGlzdCgpCgpkZi50cmFucyA8LSBhcy5kYXRhLmZyYW1lKHQoZGYpKQpkaW0oZGYudHJhbnMpCiNkZi50cmFuc1sxOjMsMTo1XQojZGltKGRmLm1ldGEpCgoKIyBMb29wIHRocm91Z2ggZWFjaCBjZWxsIHR5cGUgYW5kIHBlcmZvcm0gREVTZXEgYW5hbHlzaXMKZm9yIChpIGluIENlbGx0eXBlcykgewogICMgU3Vic2V0IHRoZSBleHByZXNzaW9uIGRhdGFmcmFtZSBieSB0aGUgY3VycmVudCBjZWxsIHR5cGUKICBwcmludChpKQogIGRmX3N1YiA8LSBkZi50cmFuc1tncmVwbChwYXN0ZTAoIl4iLGksIl8iKSwgcm93bmFtZXMoZGYudHJhbnMpKSwgXQogIHByaW50KGRpbShkZl9zdWIpKQoKICBkZi5tZXRhX3N1YiA8LSBkZi5tZXRhW2RmLm1ldGEkQ2VsbHR5cGUgPT0gaSwgXQogIHByaW50KGRpbShkZi5tZXRhX3N1YikpCiMgUHJlcGFyZSB0aGUgREVTZXEgb2JqZWN0CiAgZGZ0IDwtIGFzLmRhdGEuZnJhbWUodChkZl9zdWIpKSAjIFRyYW5zcG9zZSB0aGUgc3Vic2V0IGRhdGFmcmFtZSB0byBnZXQgZ2VuZXMgYXMgcm93cyBhbmQgc2FtcGxlcyBhcyBjb2x1bW5zCiAgZGZpIDwtIGxhcHBseShkZnQsIGFzLmludGVnZXIpCiAgZGZpIDwtIGFzLmRhdGEuZnJhbWUoZGZpKQogIHJvd25hbWVzKGRmaSkgPC0gcm93bmFtZXMoZGZ0KQoKICAKICAjIENyZWF0ZSB0aGUgREVTZXFEYXRhU2V0IG9iamVjdCB1c2luZyB0aGUgc3Vic2V0IGRhdGFmcmFtZSBhbmQgbWV0YWRhdGEKICBkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBkZmksIGNvbERhdGEgPSBkZi5tZXRhX3N1YiwgZGVzaWduID0gfkRpc2Vhc2VTdGF0dXMpCgogICMgUGVyZm9ybSBERVNlcSBhbmFseXNpcwogIGRkcyA8LSBERVNlcShkZHMpCgogICMgU3RvcmUgdGhlIERFU2VxIHJlc3VsdHMgaW4gdGhlIGxpc3Qgd2l0aCB0aGUgY2VsbCB0eXBlIGFzIHRoZSBsaXN0IGluZGV4CiAgcmVzIDwtIHJlc3VsdHMoZGRzKQogIGxpc3QyIDwtIGxpc3QoKQogIGxpc3QyW1siZGRzIl1dIDwtIGRkcwogIGxpc3QyW1sicmVzdWx0cyJdXSA8LSByZXMKICBsaXN0LnJlc3VsdHNbW2ldXSA8LSBsaXN0Mgp9CgojIFRoZSBsaXN0ICJsaXN0LnJlc3VsdHMiIG5vdyBjb250YWlucyBERVNlcSByZXN1bHRzIGZvciBlYWNoIGNlbGwgdHlwZQojIFlvdSBjYW4gYWNjZXNzIHRoZSByZXN1bHRzIGZvciBhIHNwZWNpZmljIGNlbGwgdHlwZSB1c2luZyBsaXN0LnJlc3VsdHMkQ2VsbFR5cGUKIyBGb3IgZXhhbXBsZSwgaWYgeW91IHdhbnQgdGhlIHJlc3VsdHMgZm9yIHRoZSBjZWxsIHR5cGUgIk5QQyIsIHlvdSBjYW4gYWNjZXNzIHRoZW0gdXNpbmcgbGlzdC5yZXN1bHRzW1siTlBDIl1dCgpzYXZlUkRTKGxpc3QucmVzdWx0cywgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BhcnNlRXhhbXBsZS9FeHBlcmltZW50MS1taW5pMTIvREdFYnljZWxsdHlwZUp1bHlhbm5vdGF0aW9uX2xpc3QuUkRTIikKCgpgYGAKQSBsb29rIGF0IHRoZSByZXN1bHRzCgpgYGB7cn0KCnJlcyA8LSByZXN1bHRzKGRkcykKaGVhZChyZXN1bHRzKGRkcywgdGlkeT0gVFJVRSkpCnN1bW1hcnkocmVzKQoKYGBgCmBgYHtyfQpkZHMgPC0gbGlzdC5yZXN1bHRzJE5QQyRkZHMKCnZzZGF0YSA8LSB2YXJpYW5jZVN0YWJpbGl6aW5nVHJhbnNmb3JtYXRpb24oZGRzKQoKcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwPSJEaXNlYXNlU3RhdHVzIikKcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwPSJMaW5lIikKcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwPSJCYXRjaCIpCnBsb3RQQ0EodnNkYXRhLCBpbnRncm91cD0iU2FtcGxlIikKcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwID0gIkNlbGx0eXBlIikKCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9Nn0KCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQogIEVuaGFuY2VkVm9sY2FubyhyZXMsCiAgICBsYWIgPSByb3duYW1lcyhyZXMpLAogICAgeCA9ICdsb2cyRm9sZENoYW5nZScsCiAgICB5ID0gJ3B2YWx1ZScsCiAgICB0aXRsZSA9ICdOUEMnLAogICAgeWxpbSA9IGMoMCwyMCksCiAgICBwQ3V0b2ZmID0gMC4wMSwKICAgIEZDY3V0b2ZmID0gMi41LAogICAgcG9pbnRTaXplID0gNS4wLAogICAgbGFiU2l6ZSA9IDUsIAogICAgbGVnZW5kTGFiU2l6ZSA9IDE1LAogICAgbGVnZW5kSWNvblNpemUgPSA1KQoKYGBgCgpHZXQgdGhlIERHRSBkYXRhZnJhbWUKCmBgYHtyfQoKZGYucmVzIDwtIGFzLmRhdGEuZnJhbWUobGlzdC5yZXN1bHRzJE5QQyRyZXN1bHRzKQojd3JpdGUuY3N2KGRmLnJlcywgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BhcnNlRXhhbXBsZS9FeHBlcmltZW50MS1taW5pMTIvREdFX05QQ19wc2V1ZG9idWxrX1BEdnNDb24uY3N2IikKCmhlYWQoZGYucmVzKQojZ2V0IHNvbWUgaW5mbwpwdmFsIDwtIGRmLnJlcyAlPiUgZmlsdGVyKHB2YWx1ZSA8PSAwLjAxKQpkaW0ocHZhbCkKcGFkaiA8LSBkZi5yZXMgJT4lIGZpbHRlcihwYWRqIDw9IDAuMDUpCmRpbShwYWRqKQpwYWRqIDwtIGRmLnJlcyAlPiUgZmlsdGVyKHBhZGogPD0gMC4wMSkKZGltKHBhZGopCgp1cCA8LSBwYWRqICU+JSBmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPiAwKQpkaW0odXApCmRvd24gPC0gcGFkaiAlPiUgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCkKZGltKGRvd24pCgpoZWFkKHBhZGopCgpgYGAKCkNyZWF0ZSBhIHN1bW1hcnkgZGF0YWZyYW1lIGZyb20gdGhlIERHRSAKCmBgYHtyfQoKcmVzMSA8LSBhcy5kYXRhLmZyYW1lKGxpc3QucmVzdWx0cyROZXVyb25zJHJlc3VsdHMpCgpyZXMxJENlbGx0eXBlIDwtICJOZXVyb25zIgpyZXMxJEdlbmUgPC0gcm93bmFtZXMocmVzMSkKcmVzLnNpZyA8LSAocmVzMSAlPiUgZmlsdGVyKHB2YWx1ZSA8PSAwLjA1KSkgJT4lIHNlbGVjdChjKCJHZW5lIiwiQ2VsbHR5cGUiLCJsb2cyRm9sZENoYW5nZSIsInB2YWx1ZSIsInBhZGoiKSkKcmVzLnNpZyAKCgoKYGBgCgoKU29tZSBER0UgYW5hbHlzaXMgZm9yIE5QQyB0byBjb21wYXJlCgpgYGB7cn0KCmxpYnJhcnkoZW5yaWNoUikKc2V0RW5yaWNoclNpdGUoIkVucmljaHIiKSAjIEh1bWFuIGdlbmVzCiMgbGlzdCBvZiBhbGwgdGhlIGRhdGFiYXNlcwojIGdldCB0aGUgcG9zc2libGUgbGlicmFyaWVzCmRicyA8LSBsaXN0RW5yaWNockRicygpCgojIHRoaXMgd2lsbCBsaXN0IHRoZSBwb3NzaWJsZSBsaWJyYXJpZXMKZGJzCgojIHNlbGVjdCBsaWJyYXJpZXMgd2l0aCBjZWxsIHR5cGVzCmRiIDwtIGMoJ0tFR0dfMjAxOV9IdW1hbicsJ0dXQVNfQ2F0YWxvZ18yMDE5JywiR09fQmlvbG9naWNhbF9Qcm9jZXNzXzIwMjMiLAogICAgICAgICJHT19DZWxsdWxhcl9Db21wb25lbnRfMjAyMyIsIkdPX01vbGVjdWxhcl9GdW5jdGlvbl8yMDIzIikKCiMgZnVuY3Rpb24gZm9yIGEgcXVpY2sgbG9vayAtIHRoZSBuYW1lcyBmb3IgZmlsdGVyaW5nIG5lZWQgdG8gbWF0Y2ggdGhlIGNvbHVtbiBuYW1lcwpnZXRHU0EgPC0gZnVuY3Rpb24oZGF0YWZyYW1lLCB1cF9vcl9kb3duID0gInVwIiwgTEZDdGhyZXNoID0gMC4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsX3RocmVzaCA9IDAuMDUpewogIGlmKHVwX29yX2Rvd24gPT0gInVwIil7CiAgICAgIGdlbmVsaXN0IDwtIGRhdGFmcmFtZSAlPiUgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID49IExGQ3RocmVzaCAmIHBhZGogPCBwdmFsX3RocmVzaCkKICB9ZWxzZSBpZiAodXBfb3JfZG93biA9PSAiZG93biIpIHsKICAgICAgZ2VuZWxpc3QgPC0gZGF0YWZyYW1lICU+JSBmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPD0gTEZDdGhyZXNoICYgcGFkaiA8IHB2YWxfdGhyZXNoKQogIH0gZWxzZSB7CiAgICBnZW5lbGlzdCA8LSBkYXRhZnJhbWUgJT4lIGZpbHRlcihwYWRqIDwgcHZhbF90aHJlc2gpCiAgfQpnZW5lcyA8LSBnZW5lbGlzdCRYCiAgIyB0aGUgY2VsbCB0eXBlIGxpYnJhcmllcwogICMgZ2V0IHRoZSByZXN1bHRzIGZvciBlYWNoIGxpYnJhcnkKICByZXN1bHRzIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQogICMgdmlzdWFsaXplIHRoZSByZXN1bHRzCiAgCnByaW50KHBsb3RFbnJpY2gocmVzdWx0c1tbMV1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIiwgdGl0bGUgPSAnS0VHRycpKQpwcmludChwbG90RW5yaWNoKHJlc3VsdHNbWzJdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIsIHRpdGxlID0gJ0dXQVMnKSkKcHJpbnQocGxvdEVucmljaChyZXN1bHRzW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiLCB0aXRsZSA9ICdHT2JpbycpKQpwcmludChwbG90RW5yaWNoKHJlc3VsdHNbWzRdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIsIHRpdGxlID0gJ0dPY2VsbCcpKQpwcmludChwbG90RW5yaWNoKHJlc3VsdHNbWzVdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIsIHRpdGxlID0gJ0dPbW9sJykpCnJldHVybihyZXN1bHRzKQp9CgoKCmBgYAoKYGBge3J9CiMgdXNlIG9ubHkgdGhlIHNpZ25pZmljYW50IGFmdGVyIHAgYWRqdXN0ZWQgZ2VuZXMKIyBhZGQgZ2VuZXMgY29sdW1uIHRvIERHRSBpdCBpcyBYIGlmIHNhdmVkIHRvIGNzdgpwYWRqJFggPC0gcm93bmFtZXMocGFkaikKCnBzZXVkb0RHRXVwIDwtIGdldEdTQShwYWRqLCB1cF9vcl9kb3duID0gInVwIiwKICAgICAgICAgICAgICAgIExGQ3RocmVzaCA9IDAuMDIsCiAgICAgICAgICAgICAgICBwdmFsX3RocmVzaCA9IDAuMDUpCgpgYGAKCmBgYHtyfQpwc2V1ZG9ER0Vkb3duIDwtIGdldEdTQShwYWRqLCB1cF9vcl9kb3duID0gImRvd24iLAogICAgICAgICAgICAgICAgTEZDdGhyZXNoID0gLTAuMDIsCiAgICAgICAgICAgICAgICBwdmFsX3RocmVzaCA9IDAuMDUpCmBgYAoKYGBge3J9CnBzZXVkb0RHRWRvd24gPC0gZ2V0R1NBKHBhZGosIHVwX29yX2Rvd24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICBMRkN0aHJlc2ggPSAwLAogICAgICAgICAgICAgICAgcHZhbF90aHJlc2ggPSAwLjA1KQoKYGBgCgoKCkNvbXBhcmUgZ2VuZXMgaW4gd2lsY294aW5nIHJhbmsgdmVyc2UgcHNldWRvIGJ1bGsKCmBgYHtyfQoKc2NER0UuTlBDIDwtIHJlYWQuY3N2KCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QYXJzZUV4YW1wbGUvRXhwZXJpbWVudDEtbWluaTEyL0RHRXNldXJhdE5QQ3MuY3N2IikKCmhlYWQoc2NER0UuTlBDKQoKYGBgCgoKYGBge3J9CmxpYnJhcnkoImdndmVubiIpCiMgbWFrZSB0aGUgbGlzdCBvZiB0aGUgY29tcGFyaXNvbnMgdG8gZ2V0IG51bWJlciBvZiBnZW5lcyBmb3IgdmVubgoKc2MudXAgPC0gc2NER0UuTlBDICU+JSBmaWx0ZXIoYXZnX2xvZzJGQyA+PSAwICYgcF92YWxfYWRqIDw9IDAuMDUpCnNjLmRvd24gPC0gc2NER0UuTlBDICU+JSBmaWx0ZXIoYXZnX2xvZzJGQyA8IDAgJiBwX3ZhbF9hZGogPD0gMC4wNSkKcGIudXAgPC0gcmVzMSAlPiUgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID49IDAgJiBwYWRqIDw9IDAuMDUpCnBiLmRvd24gPC0gcmVzMSAlPiUgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCAmIHBhZGogPD0gMC4wNSkKCgpjb250cmFzdC5saXN0IDwtIGxpc3QoQT0gc2MudXAkWCwgQj0gc2MuZG93biRYLCAKICAgICAgICAgICAgICAgICAgICAgIEM9cGIudXAkR2VuZSwgRD0gcGIuZG93biRHZW5lKQojIHBsb3QgdGhlIFZFTk4KCgpuYW1lcyhjb250cmFzdC5saXN0KSA8LSBjKCJzVXAiLCJzRG93biIsInBVcCIsICJwRG93biIpCmdndmVubigKICBjb250cmFzdC5saXN0LCAKICBmaWxsX2NvbG9yID0gYygiIzAwNzNDMkZGIiwgIiNFRkMwMDBGRiIsICIjODY4Njg2RkYiLCAiI0NENTM0Q0ZGIiksCiAgc3Ryb2tlX3NpemUgPSAwLjc1LCBzZXRfbmFtZV9zaXplID0gNSwgc2hvd19wZXJjZW50YWdlID0gRkFMU0UsIHRleHRfc2l6ZSA9IDUsIGZpbGxfYWxwaGEgPSAwLjc1CiAgKQoKIyBjb21wYXJlIGFsbAoKCnNjIDwtIHNjREdFLk5QQyAlPiUgZmlsdGVyKHBfdmFsX2FkaiA8PSAwLjA1KQpwYiA8LSByZXMxICU+JSBmaWx0ZXIocGFkaiA8PSAwLjA1KQoKY29udHJhc3QubGlzdCA8LSBsaXN0KEE9IHNjJFgsIEI9IHBiJEdlbmUpCiMgcGxvdCB0aGUgVkVOTgoKCm5hbWVzKGNvbnRyYXN0Lmxpc3QpIDwtIGMoInNpbmdsZSBjZWxscyIsInBzZXVkb2J1bGsiKQpnZ3Zlbm4oCiAgY29udHJhc3QubGlzdCwgCiAgZmlsbF9jb2xvciA9IGMoIiMwMDczQzJGRiIsICIjRUZDMDAwRkYiLCAiIzg2ODY4NkZGIiwgIiNDRDUzNENGRiIpLAogIHN0cm9rZV9zaXplID0gMC43NSwgc2V0X25hbWVfc2l6ZSA9IDUsIHNob3dfcGVyY2VudGFnZSA9IEZBTFNFLCB0ZXh0X3NpemUgPSA1LCBmaWxsX2FscGhhID0gMC43NQogICkKCgoKCmBgYAoKCkxvb2sgZm9yIHRoZSBvdmVybGFwcGluZyBnZW5lcwoKYGBge3J9CnNjLnVwIDwtIHNjREdFLk5QQyAlPiUgZmlsdGVyKGF2Z19sb2cyRkMgPj0gMCAmIHBfdmFsX2FkaiA8PSAwLjA1KQpzYy5kb3duIDwtIHNjREdFLk5QQyAlPiUgZmlsdGVyKGF2Z19sb2cyRkMgPCAwICYgcF92YWxfYWRqIDw9IDAuMDUpCnBiLnVwIDwtIHJlczEgJT4lIGZpbHRlcihsb2cyRm9sZENoYW5nZSA+PSAwICYgcGFkaiA8PSAwLjA1KQpwYi5kb3duIDwtIHJlczEgJT4lIGZpbHRlcihsb2cyRm9sZENoYW5nZSA8IDAgJiBwYWRqIDw9IDAuMDUpCkE9IHNjLnVwJFgKQj0gc2MuZG93biRYIApDPXBiLnVwJEdlbmUKRD0gcGIuZG93biRHZW5lCgoKdXAub3ZlcmxhcCA8LSBpbnRlcnNlY3QoQSwgQykKdXAub3ZlcmxhcAoKZG93bi5vdmVybGFwIDwtIGludGVyc2VjdChCLEQpCmRvd24ub3ZlcmxhcAoKYGBgCgoKQ2hlY2sgREdFIGJldHdlZW4gY2VsbCBsaW5lcwoKYGBge3J9Cmxpc3QucmVzdWx0cy5saW5lcyA8LSBsaXN0KCkKCmRmLnRyYW5zIDwtIGFzLmRhdGEuZnJhbWUodChkZikpCmRpbShkZi50cmFucykKI2RmLnRyYW5zWzE6MywxOjVdCiNkaW0oZGYubWV0YSkKCgojIExvb3AgdGhyb3VnaCBlYWNoIGNlbGwgdHlwZSBhbmQgcGVyZm9ybSBERVNlcSBhbmFseXNpcwpmb3IgKGkgaW4gQ2VsbHR5cGVzKSB7CiAgIyBTdWJzZXQgdGhlIGV4cHJlc3Npb24gZGF0YWZyYW1lIGJ5IHRoZSBjdXJyZW50IGNlbGwgdHlwZQogIHByaW50KGkpCiAgZGZfc3ViIDwtIGRmLnRyYW5zW2dyZXBsKHBhc3RlMCgiXiIsaSwiXyIpLCByb3duYW1lcyhkZi50cmFucykpLCBdCiAgcHJpbnQoZGltKGRmX3N1YikpCgogIGRmLm1ldGFfc3ViIDwtIGRmLm1ldGFbZGYubWV0YSRDZWxsdHlwZSA9PSBpLCBdCiAgcHJpbnQoZGltKGRmLm1ldGFfc3ViKSkKIyBQcmVwYXJlIHRoZSBERVNlcSBvYmplY3QKICBkZnQgPC0gYXMuZGF0YS5mcmFtZSh0KGRmX3N1YikpICMgVHJhbnNwb3NlIHRoZSBzdWJzZXQgZGF0YWZyYW1lIHRvIGdldCBnZW5lcyBhcyByb3dzIGFuZCBzYW1wbGVzIGFzIGNvbHVtbnMKICBkZmkgPC0gbGFwcGx5KGRmdCwgYXMuaW50ZWdlcikKICBkZmkgPC0gYXMuZGF0YS5mcmFtZShkZmkpCiAgcm93bmFtZXMoZGZpKSA8LSByb3duYW1lcyhkZnQpCgogIAogICMgQ3JlYXRlIHRoZSBERVNlcURhdGFTZXQgb2JqZWN0IHVzaW5nIHRoZSBzdWJzZXQgZGF0YWZyYW1lIGFuZCBtZXRhZGF0YQogIGRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRmaSwgY29sRGF0YSA9IGRmLm1ldGFfc3ViLCBkZXNpZ24gPSB+TGluZSkKCiAgIyBQZXJmb3JtIERFU2VxIGFuYWx5c2lzCiAgZGRzIDwtIERFU2VxKGRkcykKICAKICAKCiAgIyBTdG9yZSB0aGUgREVTZXEgcmVzdWx0cyBpbiB0aGUgbGlzdCB3aXRoIHRoZSBjZWxsIHR5cGUgYXMgdGhlIGxpc3QgaW5kZXgKICByZXMgPC0gcmVzdWx0cyhkZHMpCiAgbGlzdDIgPC0gbGlzdCgpCiAgbGlzdDJbWyJkZHMiXV0gPC0gZGRzCiAgbGlzdDJbWyJyZXN1bHRzIl1dIDwtIHJlcwogIGxpc3QucmVzdWx0cy5saW5lc1tbaV1dIDwtIGxpc3QyCn0KCgoKYGBgCgoKYGBge3J9CiMgbG9vayBhdCBzb21lIHJlc3VsdHMgCiMgTlBDCnN1bW1hcnkobGlzdC5yZXN1bHRzLmxpbmVzJE5QQyRyZXN1bHRzKQpoZWFkKGxpc3QucmVzdWx0cy5saW5lcyROUEMkcmVzdWx0cykKCnJlc3VsdHMgPC0gYXMuZGF0YS5mcmFtZShsaXN0LnJlc3VsdHMubGluZXMkTlBDJHJlc3VsdHMpCgpgYGAKClRvIHNlZSBlYWNoIGNvbnRyYXN0OgoKYGBge3J9CgojIEFzc3VtaW5nIHlvdSBoYXZlIGFscmVhZHkgcnVuIERFU2VxKCkgb24geW91ciBERVNlcURhdGFTZXQKZGRzIDwtIERFU2VxKGRkcykKCmRkcyA8LSBsaXN0LnJlc3VsdHMubGluZXMkTlBDJGRkcwojIEdldCB0aGUgbGlzdCBvZiBjb250cmFzdHMgKHBhaXJ3aXNlIGNvbXBhcmlzb25zKQphbGxfY29udHJhc3RzIDwtIGMoIlREMjJCIiwgIlREMDdCIiwgIngyOTY1QiIsICJ4MzQ0OEIiKQoKIyBJbml0aWFsaXplIGFuIGVtcHR5IGxpc3QgdG8gc3RvcmUgdGhlIHJlc3VsdHMKYWxsX3Jlc3VsdHMgPC0gbGlzdCgpCiMgTG9vcCB0aHJvdWdoIGVhY2ggY29udHJhc3QgYW5kIGNhbGN1bGF0ZSB0aGUgcmVzdWx0cwpmb3IgKGkgaW4gMTpsZW5ndGgoYWxsX2NvbnRyYXN0cykpIHsKICBmb3IgKGogaW4gKGkrMSk6bGVuZ3RoKGFsbF9jb250cmFzdHMpKSB7CiAgICBjb250cmFzdF9sZXZlbDEgPC0gYWxsX2NvbnRyYXN0c1tpXQogICAgY29udHJhc3RfbGV2ZWwyIDwtIGFsbF9jb250cmFzdHNbal0KICAgIAogICAgIyBDaGVjayBpZiBib3RoIGxldmVscyBoYXZlIGF0IGxlYXN0IG9uZSBzYW1wbGUKICAgIGlmIChzdW0oZGRzJExpbmUgPT0gY29udHJhc3RfbGV2ZWwxKSA+IDAgJiBzdW0oZGRzJExpbmUgPT0gY29udHJhc3RfbGV2ZWwyKSA+IDApIHsKICAgICAgY29udHJhc3RfbmFtZSA8LSBwYXN0ZSgiTGluZSIsIGNvbnRyYXN0X2xldmVsMSwgInZzIiwgY29udHJhc3RfbGV2ZWwyKQogICAgICBjb250cmFzdF9yZXN1bHQgPC0gcmVzdWx0cyhkZHMsIGNvbnRyYXN0ID0gYygiTGluZSIsIGNvbnRyYXN0X2xldmVsMSwgY29udHJhc3RfbGV2ZWwyKSwgbmFtZSA9IGNvbnRyYXN0X25hbWUpCiAgICAgIGFsbF9yZXN1bHRzW1tjb250cmFzdF9uYW1lXV0gPC0gY29udHJhc3RfcmVzdWx0CiAgICB9CiAgfQp9CgoKIyBOb3csIGFsbF9yZXN1bHRzIHdpbGwgY29udGFpbiB0aGUgREVTZXEgcmVzdWx0cyBmb3IgZWFjaCB2YWxpZCBjb250cmFzdAojIFlvdSBjYW4gYWNjZXNzIHRoZW0gdXNpbmcgdGhlIHJlc3BlY3RpdmUgY29udHJhc3QgbmFtZSBhcyBhbiBpbmRleAoKIyBGb3IgZXhhbXBsZSwgdG8gYWNjZXNzIHRoZSByZXN1bHRzIGZvciAiVEQyMiIgdnMgIlREMDciLCB5b3UgY2FuIHVzZToKdGQyMl92c190ZDA3X3Jlc3VsdHMgPC0gYXMuZGF0YS5mcmFtZShhbGxfcmVzdWx0cyRgTGluZSBURDIyQiB2cyBURDA3QmApCgojIEFuZCBmb3IgIngyOTY1IiB2cyAieDM0NDgiLCB5b3UgY2FuIHVzZToKeDI5NjVfdnNfeDM0NDhfcmVzdWx0cyA8LSBhcy5kYXRhLmZyYW1lKGFsbF9yZXN1bHRzJGBMaW5lIHgyOTY1QiB2cyB4MzQ0OEJgKQoKCiMgZWFjaCBjb250cmFzdCAKbGluZS5jb25zdHJhc3RzIDwtIGFsbF9yZXN1bHRzCgpoZWFkKHgyOTY1X3ZzX3gzNDQ4X3Jlc3VsdHMpCmNvbG5hbWVzKHgyOTY1X3ZzX3gzNDQ4X3Jlc3VsdHMpCgpgYGAKCmBgYHtyfQojIEluaXRpYWxpemUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSB0aGUgcmVzdWx0cwphbGxfcmVzdWx0cyA8LSBsaXN0KCkKCiMgTG9vcCB0aHJvdWdoIGVhY2ggY29udHJhc3QgYW5kIGNhbGN1bGF0ZSB0aGUgcmVzdWx0cwpmb3IgKGkgaW4gMTpsZW5ndGgoYWxsX2NvbnRyYXN0cykpIHsKICBmb3IgKGogaW4gKGkrMSk6bGVuZ3RoKGFsbF9jb250cmFzdHMpKSB7CiAgICBjb250cmFzdF9sZXZlbDEgPC0gYWxsX2NvbnRyYXN0c1tpXQogICAgY29udHJhc3RfbGV2ZWwyIDwtIGFsbF9jb250cmFzdHNbal0KICAgIAogICAgIyBDaGVjayBpZiBib3RoIGxldmVscyBhcmUgcHJlc2VudCBpbiBkZHMkTGluZQogICAgaWYgKGNvbnRyYXN0X2xldmVsMSAlaW4lIGRkcyRMaW5lICYgY29udHJhc3RfbGV2ZWwyICVpbiUgZGRzJExpbmUpIHsKICAgICAgY29udHJhc3RfbmFtZSA8LSBwYXN0ZSgiTGluZSIsIGNvbnRyYXN0X2xldmVsMSwgInZzIiwgY29udHJhc3RfbGV2ZWwyKQogICAgICBjb250cmFzdF9yZXN1bHQgPC0gcmVzdWx0cyhkZHMsIGNvbnRyYXN0ID0gYygiTGluZSIsIGNvbnRyYXN0X2xldmVsMSwgY29udHJhc3RfbGV2ZWwyKSwgbmFtZSA9IGNvbnRyYXN0X25hbWUpCiAgICAgIGFsbF9yZXN1bHRzW1tjb250cmFzdF9uYW1lXV0gPC0gY29udHJhc3RfcmVzdWx0CiAgICB9CiAgfQp9CgoKYGBgCgpgYGB7cn0KCiMgQ3JlYXRlIGEgZnVuY3Rpb24gdG8gc3VtbWFyaXplIHRoZSByZXN1bHRzIGZvciBlYWNoIGNvbnRyYXN0CnN1bW1hcml6ZV9jb250cmFzdCA8LSBmdW5jdGlvbihyZXN1bHQpIHsKICBudW1fZGVfZ2VuZXMgPC0gc3VtKHJlc3VsdCRwYWRqIDw9IDAuMDUsIG5hLnJtID0gVFJVRSkKICBudW1fZG93bnJlZ3VsYXRlZCA8LSBzdW0ocmVzdWx0JHBhZGogPD0gMC4wNSAmIHJlc3VsdCRsb2cyRm9sZENoYW5nZSA8IDAsIG5hLnJtID0gVFJVRSkKICBudW1fdXByZWd1bGF0ZWQgPC0gc3VtKHJlc3VsdCRwYWRqIDw9IDAuMDUgJiByZXN1bHQkbG9nMkZvbGRDaGFuZ2UgPiAwLCBuYS5ybSA9IFRSVUUpCiAgCiAgcmV0dXJuKGRhdGEuZnJhbWUoTnVtR2VuZXMgPSBudW1fZGVfZ2VuZXMsIE51bURvd25yZWd1bGF0ZWQgPSBudW1fZG93bnJlZ3VsYXRlZCwgTnVtVXByZWd1bGF0ZWQgPSBudW1fdXByZWd1bGF0ZWQpKQp9CgojIEluaXRpYWxpemUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSB0aGUgc3VtbWFyeSByZXN1bHRzCnN1bW1hcnlfcmVzdWx0cyA8LSBsaXN0KCkKCiMgTG9vcCB0aHJvdWdoIGVhY2ggY29udHJhc3QgYW5kIHN1bW1hcml6ZSB0aGUgcmVzdWx0cwpmb3IgKGNvbnRyYXN0X25hbWUgaW4gbmFtZXMoYWxsX3Jlc3VsdHMpKSB7CiAgY29udHJhc3RfcmVzdWx0IDwtIGFsbF9yZXN1bHRzW1tjb250cmFzdF9uYW1lXV0KICBzdW1tYXJ5X3Jlc3VsdCA8LSBzdW1tYXJpemVfY29udHJhc3QoY29udHJhc3RfcmVzdWx0KQogIHN1bW1hcnlfcmVzdWx0c1tbY29udHJhc3RfbmFtZV1dIDwtIHN1bW1hcnlfcmVzdWx0Cn0KCiMgQ29tYmluZSBhbGwgdGhlIHN1bW1hcnkgcmVzdWx0cyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUKc3VtbWFyeV90YWJsZSA8LSBkby5jYWxsKHJiaW5kLCBzdW1tYXJ5X3Jlc3VsdHMpCgojIEFkZCBhIGNvbHVtbiB3aXRoIHRoZSBjb250cmFzdCBuYW1lcyBhcyByb3cgbmFtZXMKcm93bmFtZXMoc3VtbWFyeV90YWJsZSkgPC0gbmFtZXMoYWxsX3Jlc3VsdHMpCgojIFByaW50IHRoZSBzdW1tYXJ5IHRhYmxlCnByaW50KHN1bW1hcnlfdGFibGUpCgpgYGAKCkxvb2sgYXQgb3RoZXIgY29udHJhc3RzIGluc3RlYWQgb2YgUEQgdnMgSEMgLSBIQyArIFBEIHZzIEhDICsgUEQgYW5kIHRoZSByZXZlcnNlIGNvbWJvCgoKYGBge3J9CiAKIyBhZGQgdG8gbWV0YSBkYXRhCmxpc3QucmVzdWx0cyA8LSBsaXN0KCkKCmRmLnRyYW5zIDwtIGFzLmRhdGEuZnJhbWUodChkZikpCmRpbShkZi50cmFucykKI2RmLnRyYW5zWzE6MywxOjVdCiNkaW0oZGYubWV0YSkKCmxpc3QyIDwtIGxpc3QoKQojIExvb3AgdGhyb3VnaCBlYWNoIGNlbGwgdHlwZSBhbmQgcGVyZm9ybSBERVNlcSBhbmFseXNpcwpmb3IgKGkgaW4gQ2VsbHR5cGVzKSB7CiAgIyBTdWJzZXQgdGhlIGV4cHJlc3Npb24gZGF0YWZyYW1lIGJ5IHRoZSBjdXJyZW50IGNlbGwgdHlwZQogIHByaW50KGkpCiAgZGZfc3ViIDwtIGRmLnRyYW5zW2dyZXBsKHBhc3RlMCgiXiIsaSwiXyIpLCByb3duYW1lcyhkZi50cmFucykpLCBdCiAgcHJpbnQoZGltKGRmX3N1YikpCgogIGRmLm1ldGFfc3ViIDwtIGRmLm1ldGFbZGYubWV0YSRDZWxsdHlwZSA9PSBpLCBdCiAgcHJpbnQoZGltKGRmLm1ldGFfc3ViKSkKIyBQcmVwYXJlIHRoZSBERVNlcSBvYmplY3QKICBkZnQgPC0gYXMuZGF0YS5mcmFtZSh0KGRmX3N1YikpICMgVHJhbnNwb3NlIHRoZSBzdWJzZXQgZGF0YWZyYW1lIHRvIGdldCBnZW5lcyBhcyByb3dzIGFuZCBzYW1wbGVzIGFzIGNvbHVtbnMKICBkZmkgPC0gbGFwcGx5KGRmdCwgYXMuaW50ZWdlcikKICBkZmkgPC0gYXMuZGF0YS5mcmFtZShkZmkpCiAgcm93bmFtZXMoZGZpKSA8LSByb3duYW1lcyhkZnQpCgogIAogICMgQ3JlYXRlIHRoZSBERVNlcURhdGFTZXQgb2JqZWN0IHVzaW5nIHRoZSBzdWJzZXQgZGF0YWZyYW1lIGFuZCBtZXRhZGF0YQogIGRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRmaSwgY29sRGF0YSA9IGRmLm1ldGFfc3ViLCBkZXNpZ24gPSB+RGlzZWFzZVN0YXR1cykKICAjIFBlcmZvcm0gREVTZXEgYW5hbHlzaXMKICBkZHMgPC0gREVTZXEoZGRzKQogICMgU3RvcmUgdGhlIERFU2VxIHJlc3VsdHMgaW4gdGhlIGxpc3Qgd2l0aCB0aGUgY2VsbCB0eXBlIGFzIHRoZSBsaXN0IGluZGV4CiAgcmVzIDwtIHJlc3VsdHMoZGRzKQogIGxpc3QyW1siZGRzLkRpc2Vhc2VTdGF0dXMiXV0gPC0gZGRzCiAgbGlzdDJbWyJyZXN1bHRzLkRpc2Vhc2VTdGF0dXMiXV0gPC0gcmVzCiAgCiAgIyBjaGVjayB0aGUgb3RoZXIgY2VsbCB0eXBlIGNvbWJpbmF0aW9uIG1peGVzCiAgZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gZGZpLCBjb2xEYXRhID0gZGYubWV0YV9zdWIsIGRlc2lnbiA9IH5NaXgxKQogICMgUGVyZm9ybSBERVNlcSBhbmFseXNpcwogIGRkcyA8LSBERVNlcShkZHMpCiAgIyBTdG9yZSB0aGUgREVTZXEgcmVzdWx0cyBpbiB0aGUgbGlzdCB3aXRoIHRoZSBjZWxsIHR5cGUgYXMgdGhlIGxpc3QgaW5kZXgKICByZXMgPC0gcmVzdWx0cyhkZHMpCiAgCiAgbGlzdDJbWyJkZHMuTWl4MSJdXSA8LSBkZHMKICBsaXN0MltbInJlc3VsdHMuTWl4MSJdXSA8LSByZXMKICAKICAgICMgY2hlY2sgdGhlIG90aGVyIGNlbGwgdHlwZSBjb21iaW5hdGlvbiBtaXhlcwogIGRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRmaSwgY29sRGF0YSA9IGRmLm1ldGFfc3ViLCBkZXNpZ24gPSB+TWl4MikKICAjIFBlcmZvcm0gREVTZXEgYW5hbHlzaXMKICBkZHMgPC0gREVTZXEoZGRzKQogICMgU3RvcmUgdGhlIERFU2VxIHJlc3VsdHMgaW4gdGhlIGxpc3Qgd2l0aCB0aGUgY2VsbCB0eXBlIGFzIHRoZSBsaXN0IGluZGV4CiAgcmVzIDwtIHJlc3VsdHMoZGRzKQogIGxpc3QyW1siZGRzLk1peDIiXV0gPC0gZGRzCiAgbGlzdDJbWyJyZXN1bHRzLk1peDIiXV0gPC0gcmVzCiAgCiAgbGlzdC5yZXN1bHRzLmxpbmVzW1tpXV0gPC0gbGlzdDIKfQoKCgoKYGBgClN1bW1hcml6ZSB0aGUgcmVzdWx0cyBmb3IgTlBDIGZvciB0aGUgZGlmZmVyZW50IGNvbnRyYXN0cwoKYGBge3J9CiMgZnVuY3Rpb24gY29udHJhc3RfbmFtZSBpcyBhYm92ZQoKYWxsX3Jlc3VsdHMuTlBDIDwtIGxpc3QoUER2c0hDID0gbGlzdC5yZXN1bHRzLmxpbmVzJE5QQyRyZXN1bHRzLkRpc2Vhc2VTdGF0dXMsCiAgICAgICAgICAgICAgICAgICAgICAgIE1peDEgPSBsaXN0LnJlc3VsdHMubGluZXMkTlBDJHJlc3VsdHMuTWl4MSwKICAgICAgICAgICAgICAgICAgICAgICAgTWl4MiA9IGxpc3QucmVzdWx0cy5saW5lcyROUEMkcmVzdWx0cy5NaXgyKQphbGxfcmVzdWx0cyA8LSBhbGxfcmVzdWx0cy5OUEMKCnN1bW1hcnlfcmVzdWx0cyA8LSBsaXN0KCkKIyBMb29wIHRocm91Z2ggZWFjaCBjb250cmFzdCBhbmQgc3VtbWFyaXplIHRoZSByZXN1bHRzCmZvciAoY29udHJhc3RfbmFtZSBpbiBuYW1lcyhhbGxfcmVzdWx0cykpIHsKICBjb250cmFzdF9yZXN1bHQgPC0gYWxsX3Jlc3VsdHNbW2NvbnRyYXN0X25hbWVdXQogIHN1bW1hcnlfcmVzdWx0IDwtIHN1bW1hcml6ZV9jb250cmFzdChjb250cmFzdF9yZXN1bHQpCiAgc3VtbWFyeV9yZXN1bHRzW1tjb250cmFzdF9uYW1lXV0gPC0gc3VtbWFyeV9yZXN1bHQKfQoKIyBDb21iaW5lIGFsbCB0aGUgc3VtbWFyeSByZXN1bHRzIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQpzdW1tYXJ5X3RhYmxlIDwtIGRvLmNhbGwocmJpbmQsIHN1bW1hcnlfcmVzdWx0cykKCiMgQWRkIGEgY29sdW1uIHdpdGggdGhlIGNvbnRyYXN0IG5hbWVzIGFzIHJvdyBuYW1lcwpyb3duYW1lcyhzdW1tYXJ5X3RhYmxlKSA8LSBuYW1lcyhhbGxfcmVzdWx0cykKCiMgUHJpbnQgdGhlIHN1bW1hcnkgdGFibGUKcHJpbnQoc3VtbWFyeV90YWJsZSkKCmBgYAoKSGF2ZSBhIGxvb2sgYXQgdGhlIERHRSBmb3IgTlBDCgpgYGB7cn0KCnJlcyA8LSBhbGxfcmVzdWx0cy5OUEMkUER2c0hDCnN1bW1hcnkocmVzKQoKYGBgCgpOUEMgUEQgdnMgQ29udHJvbCBWb2xjYW5vCmBgYHtyLCBmaWcuaGVpZ2h0PTN9CgojbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCnZwbG90IDwtIEVuaGFuY2VkVm9sY2FubyhyZXMsCiAgICBsYWIgPSByb3duYW1lcyhyZXMpLAogICAgeCA9ICdsb2cyRm9sZENoYW5nZScsCiAgICB5ID0gJ3B2YWx1ZScsCiAgICB5bGltID0gYygwLDIwKSwKICAgIHBDdXRvZmYgPSAwLjAxLAogICAgRkNjdXRvZmYgPSAyLjUsCiAgICBwb2ludFNpemUgPSA1LjAsCiAgICBsYWJTaXplID0gNSwgCiAgICAjbGVnZW5kTGFiU2l6ZSA9IDIwLAogICAgI3N1YnRpdGxlTGFiU2l6ZSA9IDIwLAogICAgI2xlZ2VuZEljb25TaXplID0gMTAsCiAgICApICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwKICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQoKdnBsb3QKICAgIApkZiA8LSBhcy5kYXRhLmZyYW1lKHJlcykKZGYkWCA8LSByb3duYW1lcyhkZikKcHNldWRvREdFIDwtIGdldEdTQShkZiwgdXBfb3JfZG93biA9ICJib3RoIiwKICAgICAgICAgICAgICAgIExGQ3RocmVzaCA9IDAsCiAgICAgICAgICAgICAgICBwdmFsX3RocmVzaCA9IDAuMDEpCiAgICAgICAgICAgICAgICAKCnBsb3RFbnJpY2gocHNldWRvREdFW1szXV0sIHNob3dUZXJtcyA9IDE1LCBudW1DaGFyID0gMzAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiLCB0aXRsZSA9ICdHTyBiaW9sb2d5JykgIAogIAoKYGBgCgoKCkdTRUEKCmBgYHtyfQpkZiA8LSBhcy5kYXRhLmZyYW1lKHJlcykKZGYkWCA8LSByb3duYW1lcyhkZikKcHNldWRvREdFIDwtIGdldEdTQShkZiwgdXBfb3JfZG93biA9ICJib3RoIiwKICAgICAgICAgICAgICAgIExGQ3RocmVzaCA9IDAsCiAgICAgICAgICAgICAgICBwdmFsX3RocmVzaCA9IDAuMDEpCiAgICAgICAgICAgICAgICAKcG5nKCIiKQpwbG90RW5yaWNoKHBzZXVkb0RHRVtbM11dLCBzaG93VGVybXMgPSAxNSwgbnVtQ2hhciA9IDMwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIiwgdGl0bGUgPSAnR08gYmlvbG9neScpICAKCmBgYAoKCgoKQmV0d2VlbiBiYXRjaGVzIC0gTlBDIC0gbm90IGNvbXBsZXRlCgoKYGBge3J9CgppID0gIk5QQyIKZGZfc3ViIDwtIGRmLnRyYW5zW2dyZXBsKHBhc3RlMCgiXiIsaSwiXyIpLCByb3duYW1lcyhkZi50cmFucykpLCBdCiAgcHJpbnQoZGltKGRmX3N1YikpCgogIGRmLm1ldGFfc3ViIDwtIGRmLm1ldGFbZGYubWV0YSRDZWxsdHlwZSA9PSBpLCBdCiAgcHJpbnQoZGltKGRmLm1ldGFfc3ViKSkKIyBQcmVwYXJlIHRoZSBERVNlcSBvYmplY3QKICBkZnQgPC0gYXMuZGF0YS5mcmFtZSh0KGRmX3N1YikpICMgVHJhbnNwb3NlIHRoZSBzdWJzZXQgZGF0YWZyYW1lIHRvIGdldCBnZW5lcyBhcyByb3dzIGFuZCBzYW1wbGVzIGFzIGNvbHVtbnMKICBkZmkgPC0gbGFwcGx5KGRmdCwgYXMuaW50ZWdlcikKICBkZmkgPC0gYXMuZGF0YS5mcmFtZShkZmkpCiAgcm93bmFtZXMoZGZpKSA8LSByb3duYW1lcyhkZnQpCgogIAogICMgQ3JlYXRlIHRoZSBERVNlcURhdGFTZXQgb2JqZWN0IHVzaW5nIHRoZSBzdWJzZXQgZGF0YWZyYW1lIGFuZCBtZXRhZGF0YQogIGRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRmaSwgY29sRGF0YSA9IGRmLm1ldGFfc3ViLCBkZXNpZ24gPSB+QmF0Y2gpCgogIHJlcyA8LSByZXN1bHRzKGRkcykKCmBgYAoKCiMgU2F2ZSBDU1Ygb2YgZWFjaCByZXN1bHQgZnJvbSBhIERHRQoKYGBge3J9CgoKCgpgYGAKCiMgUmVuYW1lIGZ1bmN0aW9uIC0gdG8gc2VlCgoK